Spring 原始碼學習 04:初始化容器與 DefaultListableBeanFactory
阿新 • • 發佈:2020-12-03
#### 前言
![](https://cdn.jsdelivr.net/gh/liuzhihang/oss/pic/article/Sf8fRH-D6nt5n.png)
在前一篇文章:[建立 IoC 容器的幾種方式](https://mp.weixin.qq.com/s/V7SjmIFKAXyppBF_KHbxXQ)中,介紹了四種方式,這裡以 `AnnotationConfigApplicationContext` 為例,跟進程式碼,看看 IoC 的啟動流程。
### 入口
從 JavaConfig 中載入配置的 `AnnotationConfigApplicationContext` 啟動方式如下:
![](https://cdn.jsdelivr.net/gh/liuzhihang/oss/pic/article/NbaqT1-SIKlXs.png)
進去之後發現構造其實是呼叫的當前無參構造。
![](https://cdn.jsdelivr.net/gh/liuzhihang/oss/pic/article/dA7SqR-pnWaJ0.png)
所以在啟動時也可以直接宣告無參構造,改寫為下面這種:
```java
public class AnnotationConfigApplicationTest {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.register(JavaConfig.class);
context.refresh();
System.out.println(context.getBean(UserComponent.class));
}
}
```
今天就研究研究無參構造這一部分究竟做了什麼邏輯!
#### 無參構造
![](https://cdn.jsdelivr.net/gh/liuzhihang/oss/pic/article/VfQDRi-qtFJay.png)
其中的 `StartupStep` 是 5.3 新增的類,看程式碼註釋的意思是:表示用來記錄啟動過程中的一些指標資訊等。暫時不做研究。
主要研究紅框部分!注意,**這一塊並不代表只有紅框部分**!
![](https://cdn.jsdelivr.net/gh/liuzhihang/oss/pic/article/jHZiO9-lClEgy.png)
因為 `AnnotationConfigApplicationContext` 繼承了 `GenericApplicationContext`,所以會先執行父類的構造方法。
![](https://cdn.jsdelivr.net/gh/liuzhihang/oss/pic/article/T9dF4r-BeA6nA.png)
所以這裡會建立一個 `DefaultListableBeanFactory` 的容器。
### DefaultListableBeanFactory
![DefaultListableBeanFactory UML](https://cdn.jsdelivr.net/gh/liuzhihang/oss/pic/article/DefaultListableBeanFactory-oBHX69.png)
雖然說 Spring 的 `BeanFactory` 定義了容器的基礎概念、介面方法等,但是 `DefaultListableBeanFactory` 才是一個真正可以 new 出來的具體的容器,當然也可以暫且稱之為 bean 工廠。
下面來看一下 `DefaultListableBeanFactory` 裡面都有什麼?
![](https://cdn.jsdelivr.net/gh/liuzhihang/oss/pic/article/oUgw6b-dgE9ZX.png)
在 `DefaultListableBeanFactory` 裡面會初始化很多引數,其中重點關注的是下面兩個引數:
```java
/** Map of bean definition objects, keyed by bean name. */
// BeanDefinition 的儲存 Map 其中 key 為 beanName
private final Map beanDefinitionMap = new ConcurrentHashMap<>(256);
/** List of bean definition names, in registration order. */
// BeanName 的集合
private volatile List beanDefinitionNames = new ArrayList<>(256);
```
其中 `BeanDefinition` 描述了一個 bean 例項,該例項具有屬性值,建構函式引數值以及具體實現所提供的更多資訊。
對應的 `beanDefinitionMap` 就是儲存的初始化的 beanName 和 BeanDefinition。
至於 BeanDefinition 具體內容,下一節再做介紹。
### 總結
通過上面的閱讀,可以在初始化流程中增加一部分模組,即例項化 `DefaultListableBeanFactory`
![](https://cdn.jsdelivr.net/gh/liuzhihang/oss/pic/article/m4P5ZW-VrZwt7.png)
再回顧一下 `DefaultListableBeanFactory` 的概念。
>**DefaultListableBeanFactory:**
>
>Spring 的 ConfigurableListableBeanFactory 和 BeanDefinitionRegistry 介面的預設實現:基於bean定義元資料的成熟bean工廠,可通過後處理器進行擴充套件。
>重點需要把握的是 DefaultListableBeanFactory 內部定義了 BeanDefinition 的 Map。
#### 結束語
本文從入口開始,進入到構造,主要介紹了 `DefaultListableBeanFactory` 的建立,及建立時初始化了一堆引數。
考慮到文章篇幅問題,儘量避免大段大段的貼程式碼以及註釋,有興趣的小夥伴可以試著自己搭建原始碼構建環境,然後 Debug 走一走,這樣也可以互相探討,共同學習。
筆者也是剛開始閱讀學習原始碼,不足之處,希望多多指正。
#### 相關推薦
- [Spring 原始碼學習 03:建立 IoC 容器的幾種方式](https://mp.weixin.qq.com/s/V7SjmIFKAXyppBF_KHbxXQ)
- [Spring 原始碼學習 02:關於 Spring IoC 和 Bean 的概念](https://mp.weixin.qq.com/s/YPDPU7ePtii0vlrynexb_w)
- [Spring 原始碼學習 01:原始碼閱讀環境的搭建](https://mp.weixin.qq.com/s/gDhJMSPSX2vz68p5