SpringFramework之IoC容器初始化
阿新 • • 發佈:2020-03-30
**原創文章,轉發請標註https://www.cnblogs.com/boycelee/p/12595884.html**
[toc]
## 分析例子
#### 啟動類
Application,使用的是ClassPathXmlApplicationContext來載入xml檔案
```java
/**
* @author jianw.li
* @date 2020/3/16 11:53 PM
* @Description: TODO
*/
public class MyApplication {
private static final String CONFIG_LOCATION = "classpath:application_context.xml";
private static final String BEAN_NAME = "hello";
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext(CONFIG_LOCATION);
Hello hello = (Hello) ac.getBean(BEAN_NAME);
hello.sayHello();
}
}
```
#### Bean
```java
/**
* @author jianw.li
* @date 2020/3/16 11:53 PM
* @Description: TODO
*/
public class Hello {
public void sayHello() {
System.out.println("Hello World");
}
}
```
#### 配置檔案
在resources下建立名為classpath:application_context.xml的配置檔案,並配置好Bean
```xml
```
## 總體結構
**ClassPathXmlApplicationContext繼承體系如下:**
![KWJf7l](https://gitee.com/leeboyce/imagebed/raw/20200305-image/uPic/KWJf7l.png)
**IoC總體結構圖如下:**
![image-20200322155805716](https://gitee.com/leeboyce/imagebed/raw/20200305-image/uPic/image-20200322155805716.png)
## 原始碼分析
#### ClassPathXmlApplicationContext
```java
//建構函式,建立ClassPathXmlApplicationContext,其中configLocation為Bean所在的檔案路徑
public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
this(new String[] {configLocation}, true, null);
}
public ClassPathXmlApplicationContext(
String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
throws BeansException {
//null
super(parent);
//設定配置路徑至ApplicationContext中
setConfigLocations(configLocations);
if (refresh) {
//核心方法,refresh會將舊的ApplicaionContext銷燬
refresh();
}
}
```
#### AbstractApplicationContext
##### refresh
核心方法,refresh銷燬舊ApplicationContext,生成新的ApplicationContext
```java
@Override
public void refresh() throws BeansException, IllegalStateException {
//加鎖.沒有明確物件,只是想讓一段程式碼同步,可以建立Object startupShutdownMonitor = new Object()
synchronized (this.startupShutdownMonitor) {
// 為context重新整理準備.設定啟動時間,設定啟用狀態等
prepareRefresh();
// 告知子類重新整理內部bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
initMessageSource();
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
onRefresh();
// Check for listener beans and register them.
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
//初始化所有未懶載入單例
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
//廣播初始化完成
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}
```
##### obtainFreshBeanFactory
告知子類重新整理內部bean factory.
核心方法,初始化BeanFactory、載入Bean、註冊Bean
```java
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
//重新整理Bean工廠,關閉並銷燬舊BeanFacroty
refreshBeanFactory();
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (logger.isDebugEnabled()) {
logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
}
return beanFactory;
}
```
##### refreshBeanFactory
關閉並銷燬舊BeanFactory,建立與初始化新BeanFactory。**為什麼是DefaultListableBeanFactory?**
```java
@Override
protected final void refreshBeanFactory() throws BeansException {
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
//初始化DefaultListableBeanFactory,為什麼選擇例項化DefaultListableBeanFactory?而不是其他的Bean工廠
DefaultListableBeanFactory beanFactory = createBeanFactory();
//Bean工廠序列化設定id
beanFactory.setSerializationId(getId());
//定製Bean工廠,設定不允許覆蓋Bean,不允許迴圈依賴等
customizeBeanFactory(beanFactory);
//將Bean載入至Bean工廠中
loadBeanDefinitions(beanFactory);
//此處synchronized塊與#hasBeanFactory中的synchronized塊存在關聯,此處鎖住之後hasBeanFactory中的synchronized塊將等待
//避免beanFactory未銷燬或未關閉的情況
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}
```
##### customizeBeanFactory
定製BeanFactory。設定Bean覆蓋、迴圈依賴等。**什麼是迴圈依賴?**
```
protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
if (this.allowBeanDefinitionOverriding != null) {
//預設值為false不允許對Bean進行覆蓋
beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
if (this.allowCircularReferences != null) {
//預設值為false,不允許迴圈依賴
beanFactory.setAllowCircularReferences(this.allowCircularReferences);
}
}
```
#### AbstractXmlApplicationContext
##### loadBeanDefinitions
```java
@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
// Create a new XmlBeanDefinitionReader for the given BeanFactory.
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
// Configure the bean definition reader with this context's
// resource loading environment.
beanDefinitionReader.setEnvironment(this.getEnvironment());
beanDefinitionReader.setResourceLoader(this);
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
// Allow a subclass to provide custom initialization of the reader,
// then proceed with actually loading the bean definitions.
initBeanDefinitionReader(beanDefinitionReader);
loadBeanDefinitions(beanDefinitionReader);
}
```
##### loadBeanDefinitions
```java
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
Resource[] configResources = getConfigResources();
if (configResources != null) {
//載入資源物件,最終還是會回到這種方式去載入bean.
reader.loadBeanDefinitions(configResources);
}
String[] configLocations = getConfigLocations();
if (configLocations != null) {
//載入資源路徑嗎
reader.loadBeanDefinitions(configLocations);
}
}
```
#### AbstractBeanDefinitionReader
##### loadBeanDefinitions
```java
@Override
public int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException {
Assert.notNull(locations, "Location array must not be null");
int counter = 0;
//迴圈配置檔案路徑
for (String location : locations) {
counter += loadBeanDefinitions(location);
}
return counter;
}
```
```java
public int loadBeanDefinitions(String location, @Null