1. 程式人生 > >Spring IOC 容器預啟動流程原始碼探析

Spring IOC 容器預啟動流程原始碼探析

# Spring IOC 容器預啟動流程原始碼探析 在應用程式中,一般是通過建立`ClassPathXmlApplicationContext`或`AnnotationConfigApplicationContext`這兩個最底層子類來啟動Spring IOC容器: - `ClassPathXmlApplicationContext`: `xml`檔案配置版 - `AnnotationConfigApplicationContext`: 註解版 由於當下越來越流行基於Java註解的配置來建立我們的`Bean`,所以本文主要以註解版進行探析。 ## `AnnotationConfigApplicationContext`的類關係結構 我們先來看看我們探討的起點 ```java public class Main { public static void main(String[] args) { new AnnotationConfigApplicationContext(Config.class); } @Configuration public static class Config{ } } ``` demo簡簡單單,那麼,這裡發生了什麼?或許,我們可以先看看`AnnotationConfigApplicationContext`的類關係結構: ![在這裡插入圖片描述](https://img2020.cnblogs.com/other/1187061/202010/1187061-20201012160623512-1644137921.png) 我們可以看到`AnnotationConfigApplicationContext`最上面有兩個頂級介面: - `BeanFactory`: Spring的核心介面,純粹的bean容器,主要定義了與`Bean`的相關方法 - `ResourceLoader`:資源載入器,定義了`getResource`方法 繼承自三個父類: - `DefaultResourceLoader`: 預設的資源載入器,實現了三種載入資源的方式 1. 通過`path`載入資源 2. 通過`classpath`載入資源 3. 通過`URL`載入資源 - `AbstractApplicationContext`: 實現了`ApplicationContext`介面的抽象類,主要功能 1. 實現了啟動IOC容器的核心方法:`refresh()` 2. 釋出事件 3. 大量`getBean`相關的操作, 主要通過抽象方法`getBeanFactory`基於子類實現 4. 大量留於子類擴充套件的空方法 5. 訊息國際化 - `GenericApplicationContext`: 1. 使用組合的方式引進了最底層的`BeanFactory`實現類:`DefaultListableBeanFactory` 2. 定義了`registerBean`的相關操作,其實是通過`DefaultListableBeanFactory`實現的 > 不難發現,`ApplicationContext`名副其實,確實就是一個應用上下文,對於`bean`的相關操作,容器的管理,依舊是由我們的`BeanFactory`進行實現。 ## 準備啟動 ### 1. 建立我們的例項:`AnnotationConfigApplicationContext` ```java new AnnotationConfigApplicationContext(Config.class); ``` ### 2.進入到`AnnotationConfigApplicationContext`構造方法 ```java public AnnotationConfigApplicationContext(Class... annotatedClasses) { this(); register(annotatedClasses); refresh(); } ``` ### 3. 呼叫我們的空構造方法,這裡要先例項化我們的父類 #### 3.1 例項化`DefaultResourceLoader` ```java public DefaultResourceLoader() { this.classLoader = ClassUtils.getDefaultClassLoader(); } ``` `ClassUtils.getDefaultClassLoader()`主要有兩步操作 ```java //獲取執行緒上下文的類載入器 ClassLoader cl = = Thread.currentThread().getContextClassLoader(); if(cl == null) //為空則獲取系統的類載入器 即為應用類載入器 cl = ClassLoader.getSystemClassLoader(); ``` > 這裡我們非Tomcat環境,所以返回的是AppClassLoader #### 3.2 例項化`AbstractApplicationContext` ```java //為BeanFactoryPostProcessor賦初始