Spring IOC 容器預啟動流程原始碼探析
阿新 • • 發佈:2020-10-12
# 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賦初始