1. 程式人生 > 其它 >Spring IOC原始碼(一):IOC容器啟動流程核心方法概覽

Spring IOC原始碼(一):IOC容器啟動流程核心方法概覽

 Spring有兩種方式載入配置,分別為xml檔案、註解的方式,對於xml配置的方式相信大家都不陌生,往往通過new ClassPathXmlApplicationContext("*.xml")就能啟動容器了,下面讓我們來看看Spring的容器啟動都做了哪些事情。

1、ClassPatchXmlApplicationContext的類圖結構

從類圖我們可以得到的資訊:   1,ClassPatchXmlApplicationContext是一個容器 ,是BeanFactory的子類;   2,ClassPatchXmlApplicationContext是一個資源載入器,是ResourceLoader的子類。

2、ClassPatchXmlApplicationContext構造器

 1 public ClassPathXmlApplicationContext(
 2       String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
 3       throws BeansException {
 4    // 呼叫父類構造方法
 5    super(parent);
 6    // 資源路徑設定到當前上下文中
 7    setConfigLocations(configLocations);
 8    // 重新整理容器
 9    if (refresh) {
10       refresh();
11    }
12 }

2.1、呼叫父類構造器

  最終會呼叫到父類AbstractApplicationContext的構造方法。   1、初始化AbstractApplicationContext的資源路徑解析器resourcePatternResolver 屬性;   2、為當前上下文設定父上下文環境,若父上下文環境不為空,將父上下文環境合併到當前上下文環境中。
 1 // 構造器
 2 public AbstractApplicationContext(@Nullable ApplicationContext parent) {
 3    this();
 4    setParent(parent);
 5 }
 6 // 初始化資源路徑解析器
 7 public AbstractApplicationContext() {
 8    // 建立資源模式處理器
 9    this.resourcePatternResolver = getResourcePatternResolver();
10 }
11 // 設定父容器
12 public void setParent(@Nullable ApplicationContext parent) {
13    this.parent = parent;
14    // 若父容器不為空,則將父容器的環境配置合併到當前容器中
15    if (parent != null) {
16       Environment parentEnvironment = parent.getEnvironment();
17       if (parentEnvironment instanceof ConfigurableEnvironment) {
18          getEnvironment().merge((ConfigurableEnvironment) parentEnvironment);
19       }
20    }
21 }

2.2、設定資源路徑

  對父類AbstractRefreshableConfigApplicationContext的configLocations做賦值,將配置資源配置檔案位置設定到當前應用程式上下文中。
 1 // 設定資源路徑
 2 public void setConfigLocations(@Nullable String... locations) {
 3    if (locations != null) {
 4       Assert.noNullElements(locations, "Config locations must not be null");
 5       this.configLocations = new String[locations.length];
 6       for (int i = 0; i < locations.length; i++) {
 7          this.configLocations[i] = resolvePath(locations[i]).trim();
 8       }
 9    }
10    else {
11       this.configLocations = null;
12    }
13 }

2.3、重新整理容器 - Spring的IOC容器的核心啟動流程

 1 // 重新整理容器的流程
 2 @Override
 3 public void refresh() throws BeansException, IllegalStateException {
 4    synchronized (this.startupShutdownMonitor) {
 5       // 容器重新整理前的準備工作
 6       prepareRefresh();
 7       // 建立容器物件DefaultListableBeanFactory,載入xml配置檔案的屬性值到當前工廠中
 8       ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
 9       // beanFactory的準備工作,對各種屬性進行填充
10       prepareBeanFactory(beanFactory);
11 
12       try {
13          // 子類覆蓋方法做額外的處理,web中的程式碼有具體實現
14          postProcessBeanFactory(beanFactory);
15 
16          // 呼叫各種beanFactory處理器
17          invokeBeanFactoryPostProcessors(beanFactory);
18 
19          // 註冊bean處理器,這裡只是註冊功能,真正呼叫的地方在getBean方法
20          registerBeanPostProcessors(beanFactory);
21 
22          // 為上下文初始化message源,即不同語言的訊息體,國際化處理,在springmvc的有實際應用
23          initMessageSource();
24 
25          // 初始化事件監聽多路廣播器
26          initApplicationEventMulticaster();
27 
28          // 留給子類來初始化其他的bean
29          onRefresh();
30 
31          // 在所有註冊的bean中查詢listener bean,註冊到訊息廣播器中
32          registerListeners();
33 
34          // 初始化剩下的單例項(非懶載入的)
35          finishBeanFactoryInitialization(beanFactory);
36 
37          // 完成重新整理過程,通知生命週期處理器lifecycleProcessor重新整理過程,同時發出ContextRefreshEvent通知
38          finishRefresh();
39       }
40 
41       catch (BeansException ex) {
42          if (logger.isWarnEnabled()) {
43             logger.warn("Exception encountered during context initialization - " +
44                   "cancelling refresh attempt: " + ex);
45          }
46 
47          // 為防止bean資源佔用,在異常處理中,銷燬已經在前面過程中生成的單件bean
48          destroyBeans();
49 
50          // 重置active標誌
51          cancelRefresh(ex);
52 
53          throw ex;
54       }
55       finally {
56          // 重置快取
57          resetCommonCaches();
58       }
59    }
60 }

綜上可見,Spring容器啟動的核心方法,這些方法後序會做詳細介紹

1、prepareRefresh()

  重新整理容器前的準備工作

2、obtainFreshBeanFactory()

  建立容器,並載入配置並生成BeanDefinition,載入至快取。為後續建立bean物件做準備工作。

3、prepareBeanFactory(beanFactory)

  beanFactory的準備工作,主要是用來為容器填充屬性

4、postProcessBeanFactory(beanFactory)

  beanFactory容器的後置處理器

5、invokeBeanFactoryPostProcessors(beanFactory)

  呼叫各種BeanFactoryPostProcessors的後置處理器,例項化BeanFactoryPostProcessor型別的bean物件,包括ConfigurationClassPosyProcessor類對註解的處理,也是SpringBoot自動配置的基礎。

6、registerBeanPostProcessors(beanFactory)

  呼叫各種BeanPostProcessor的後置處理器,例項化BeanPostProcessor型別的bean物件,包括對Spring AOP的自動代理建立器AspectJAwareAdvisorAutoProxyCreator的例項的建立。

7、finishBeanFactoryInitialization(beanFactory)

  初始化定義的bean例項。

8、finishRefresh()

  完成重新整理過程,通知生命週期處理器lifecycleProcessor重新整理過程