最近磕Spring源碼有一段時間,直接上手閱讀的難度還是非常大,體系龐大且分支線繁雜,我在閱讀的時候,進入各種實現(xiàn)類很容易繞的不知所蹤了,因此打算把閱讀的Spring源碼做一個總結,把核心脈絡給梳理出來,后面根據(jù)Spring的核心實現(xiàn)也嘗試自己去手寫一個簡易版的Easy-Spring項目,體會下手擼造輪子的感覺。
IoC容器的頂級類:BeanFactory,負責生產(chǎn) bean 的工廠,同時管理各個 bean 實例,可以先來看下和 BeanFactory 接口相關的主要的繼承結構:

除了 BeanFactory 接口外,還有一個重要的 ApplicationContext 其實就是一個 BeanFactory,但是BeanFactory 只提供了最簡單的容器的功能(實例化對象和拿對象的功能),所以被稱為低級容器,而ApplicationContext 則是一個高級的容器,提供了更多的有用的功能,如國際化、訪問資源、消息發(fā)送、響應機制等。下面就從IoC容器的啟動開始講起:
Refresh主流程
首先是IoC的容器啟動,第一步要從 ClassPathXmlApplicationContext 的構造方法說起,通過分析ClassPathXmlApplicationContext類,首先是調用自己的構造方法,然后開始調用最重要的refresh()方法,容器可以去調用 refresh() 這個方法重建ApplicationContext 的,refresh()會將原來的 ApplicationContext 銷毀,然后再重新執(zhí)行一次初始化操作。此處貼上最核心的refresh()方法源碼與解析:
@Override
public void refresh() throws BeansException, IllegalStateException {
// 來個鎖,不然 refresh() 還沒結束,你又來個啟動或銷毀容器的操作,那不就亂套了嘛
synchronized (this.startupShutdownMonitor) {
// 準備工作,記錄下容器的啟動時間、標記“已啟動”狀態(tài)、處理配置文件中的占位符
prepareRefresh();
// 這步比較關鍵,這步完成后,配置文件就會解析成一個個 Bean 定義,注冊到 BeanFactory 中,
// 當然,這里說的 Bean 還沒有初始化,只是配置信息都提取出來了,
// 注冊也只是將這些信息都保存到了注冊中心(說到底核心是一個 beanName-> beanDefinition 的 map)
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 設置 BeanFactory 的類加載器,添加幾個 BeanPostProcessor,手動注冊幾個特殊的 bean
// 這塊待會會展開說
prepareBeanFactory(beanFactory);
try {
// 【這里需要知道 BeanFactoryPostProcessor 這個知識點,Bean 如果實現(xiàn)了此接口,
// 那么在容器初始化以后,Spring 會負責調用里面的 postProcessBeanFactory 方法?!?
// 這里是提供給子類的擴展點,到這里的時候,所有的 Bean 都加載、注冊完成了,但是都還沒有初始化
// 具體的子類可以在這步的時候添加一些特殊的 BeanFactoryPostProcessor 的實現(xiàn)類或做點什么事
postProcessBeanFactory(beanFactory);
// 調用 BeanFactoryPostProcessor 各個實現(xiàn)類的 postProcessBeanFactory(factory) 回調方法
invokeBeanFactoryPostProcessors(beanFactory);
// 注冊 BeanPostProcessor 的實現(xiàn)類,注意看和 BeanFactoryPostProcessor 的區(qū)別
// 此接口兩個方法: postProcessBeforeInitialization 和 postProcessAfterInitialization
// 兩個方法分別在 Bean 初始化之前和初始化之后得到執(zhí)行。這里僅僅是注冊,之后會看到回調這兩方法的時機
registerBeanPostProcessors(beanFactory);
// 初始化當前 ApplicationContext 的 MessageSource,國際化這里就不展開說了,不然沒完沒了了
initMessageSource();
// 初始化當前 ApplicationContext 的事件廣播器,這里也不展開了
initApplicationEventMulticaster();
// 從方法名就可以知道,典型的模板方法(鉤子方法),不展開說
// 具體的子類可以在這里初始化一些特殊的 Bean(在初始化 singleton beans 之前)
onRefresh();
// 注冊事件監(jiān)聽器,監(jiān)聽器需要實現(xiàn) ApplicationListener 接口。這也不是我們的重點,過
registerListeners();
// 重點,重點,重點
// 初始化所有的 singleton beans
//(lazy-init 的除外)
finishBeanFactoryInitialization(beanFactory);
// 最后,廣播事件,ApplicationContext 初始化完成,不展開
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.
// 銷毀已經(jīng)初始化的 singleton 的 Beans,以免有些 bean 會一直占用資源
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// 把異常往外拋
throw ex;
}
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}
主要去看兩個關鍵方法:
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();finishBeanFactoryInitialization(beanFactory);
上面的obtainFreshBeanFactory方法是去按照配置文件就會解析成一個個 Bean 定義,注冊到 BeanFactory 中,此處的Bean 還沒有初始化,只是配置信息都提取出來了,保存到了DefaultListableBeanFactory類里面的一個線程安全的HashMap中:
DefaultListableBeanFactory.java,166行
/** Map of bean definition objects, keyed by bean name. */
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
而下一個finishBeanFactoryInitialization方法則是去初始化所有的singleton beans,因此這篇文章也主要是圍繞著 refresh 這兩個關鍵方法去梳理工作流程和脈絡。
一、obtainFreshBeanFactory方法
1. 首先,是創(chuàng)建 Bean 容器前的準備工作:
// 準備工作,記錄下容器的啟動時間、標記“已啟動”狀態(tài)、處理配置文件中的占位符
prepareRefresh();
2. 創(chuàng)建 Bean 容器,加載并注冊 Bean
這里有一個obtainFreshBeanFactory()。注意,這個方法是全文最重要的部分之一,這里將會初始化 BeanFactory、加載 Bean、注冊 Bean等等。
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
refreshBeanFactory();
return getBeanFactory();
}
這個時候找一下 AbstractRefreshableApplicationContext.java 中的refreshBeanFactory()方法,這里要注意的是這一段:
// 加載 Bean 到 BeanFactory 中
loadBeanDefinitions(beanFactory);
BeanFactory 是 Bean 容器,那么 Bean 又是什么呢? BeanDefinition 就是我們所說的 Spring 的 Bean,我們自己定義的各個 Bean 其實會轉換成一個個 BeanDefinition 存在于 Spring 的 BeanFactory 中。Bean 在代碼層面上可以簡單認為是 BeanDefinition 的實例。
BeanDefinition 中保存了我們的 Bean 信息,比如這個 Bean 指向的是哪個類、是否是單例的、是否懶加載、這個 Bean 依賴了哪些 Bean 等等。注意這個里面沒有getInstance()獲取實例的方法
總結一下:到 refresh 中的 obtainFreshBeanFactory 方法,Bean 還沒有初始化,只是配置信息都提取出來了,注冊也只是將這些信息都保存到了注冊中心(說到底核心是一個 beanName-> beanDefinition 的 map)。
二、finishBeanFactoryInitialization方法
這個 finishBeanFactoryInitialization 方法就是要去初始化所有的 singleton beans,換句話說:Spring 會在這個階段完成所有的 singleton beans 的實例化。首先進入到 AbstractApplicationContext 類里面的 finishBeanFactoryInitialization 方法:
// AbstractApplicationContext.java 834
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
// 開始初始化
beanFactory.preInstantiateSingletons();
}
又要換一個實現(xiàn)類 DefaultListableBeanFactory 才開始做初始化工作,這里要分兩種情況,是否為工廠Bean類型
// DefaultListableBeanFactory 728
public void preInstantiateSingletons() throws BeansException {
// FactoryBean 的話,在 beanName 前面加上 ‘&’ 符號。再調用 getBean,getBean 方法別急
final FactoryBean<?> factory = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName);
// 對于普通的 Bean,只要調用 getBean(beanName) 這個方法就可以進行初始化了
getBean(beanName);
}
AbstractBeanFactory類
接下來,我們就進入到非常重要的 AbstractBeanFactory 類里面的 getBean(beanName) 方法了,這個方法我們經(jīng)常用來從 BeanFactory 中獲取一個 Bean,初始化的getBean也在這個方法里封裝。這里的流程大致概括一下就是:
- 1、先處理Bean 的名稱,因為如果以“&”開頭的Bean名稱表示獲取的是對應的 FactoryBean 對象;
- 2、從緩存中獲取單例Bean,有則進一步判斷這個Bean是不是在創(chuàng)建中,如果是的就等待創(chuàng)建完畢,否則直接返回這個Bean對象
- 3、如果不存在單例Bean緩存,則先進行循環(huán)依賴的解析
- 4、解析完畢之后先獲取父類BeanFactory,獲取到了則調用父類的getBean方法,不存在則先合并然后創(chuàng)建Bean
// AbstractBeanFactory 196
@SuppressWarnings("unchecked")
protected <T> T doGetBean(
final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
throws BeansException {
// 獲取一個 “正統(tǒng)的” beanName,處理兩種情況,一個是前面說的 FactoryBean(前面帶 ‘&’),
// 一個是別名問題,因為這個方法是 getBean,獲取 Bean 用的,你要是傳一個別名進來,是完全可以的
final String beanName = transformedBeanName(name);
// 檢查下是不是已經(jīng)創(chuàng)建過了
Object sharedInstance = getSingleton(beanName);
// 檢查一下這個 BeanDefinition 在容器中是否存在
BeanFactory parentBeanFactory = getParentBeanFactory();
// 先初始化依賴的所有 Bean,這個很好理解。
// 注意,這里的依賴指的是 depends-on 中定義的依賴
String[] dependsOn = mbd.getDependsOn();
// 如果是 singleton scope 的,創(chuàng)建 singleton 的實例
if (mbd.isSingleton()) {
return createBean(beanName, mbd, args);
}
}
把上面的代碼串起來一張流程圖是長這個樣子的:
假設這個是第一次去初始化bean那么就會走入到本 AbstractBeanFactory 類里面一個虛函數(shù)中去:
protected abstract Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) throws BeanCreationException;
AbstractAutowireCapableBeanFactory類
AbstractAutowireCapableBeanFactory 這個類會實現(xiàn)createBean的方法,主要是在真正創(chuàng)建bean之前做一些前置的檢查條件,可以很快過一下,進入到真正的 doCreateBean 方法中去。
// AbstractAutowireCapableBeanFactory 447
protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) throws BeanCreationException {
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
}
接下來我們挑 doCreateBean 中的三個細節(jié)出來說說。流程圖如下:
- 1、先檢查 instanceWrapper變量是不是null,這里一般是null,除非當前正在創(chuàng)建的Bean在 factoryBeanInstanceCache中存在這個是保存還沒創(chuàng)建完成的FactoryBean的集合。
- 2、調用createBeanInstance方法實例化Bean,這個方法在后面會講解
- 3、如果當前 RootBeanDefinition對象還沒有調用過實現(xiàn)了的 MergedBeanDefinitionPostProcessor 接口的方法,則會進行調用 。
- 4、 當滿足以下三點(1)是單例Bean,(2)嘗試解析bean之間的循環(huán)引用,(3)bean目前正在創(chuàng)建中
則會進一步檢查是否實現(xiàn)了 SmartInstantiationAwareBeanPostProcessor接口如果實現(xiàn)了則調用是實現(xiàn)的 getEarlyBeanReference方法 - 5、 調用 populateBean方法進行屬性填充,這里后面會講解
- 6、 調用 initializeBean方法對Bean進行初始化,這里后面會講解
把上面的核心步驟抽取出來也就是三個方法:一個是創(chuàng)建 Bean 實例的 createBeanInstance 方法,一個是依賴注入的 populateBean 方法,還有就是回調方法 initializeBean。抽取執(zhí)行的關鍵代碼位置就在如下三處:
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)
throws BeanCreationException {
if (instanceWrapper == null) {
// 說明不是 FactoryBean,這里實例化 Bean,這里非常關鍵,細節(jié)之后再說
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
try {
// 這一步也是非常關鍵的,這一步負責屬性裝配,因為前面的實例只是實例化了,并沒有設值,這里就是設值
populateBean(beanName, mbd, instanceWrapper);
if (exposedObject != null) {
// 還記得 init-method 嗎?還有 InitializingBean 接口?還有 BeanPostProcessor 接口?
// 這里就是處理 bean 初始化完成后的各種回調
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
} catch (Throwable ex) {}
}
a.創(chuàng)建 Bean 實例
我們先看看 createBeanInstance 方法。需要說明的是,這個方法如果每個分支都分析下去,必然也是極其復雜冗長的,我們挑重點說。此方法的目的就是實例化我們指定的類。
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) {
// 調用無參構造函數(shù)
return instantiateBean(beanName, mbd);
}
挑個簡單的無參構造函數(shù)構造實例來看看:
protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) {
// 實例化,關鍵的地方
beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);
}
// SimpleInstantiationStrategy 59
public Object instantiate(RootBeanDefinition bd, String beanName, BeanFactory owner) {
// 如果不存在方法覆寫,那就使用 java 反射進行實例化,否則使用 CGLIB,
// 方法覆寫 請參見附錄"方法注入"中對 lookup-method 和 replaced-method 的介紹
if (bd.getMethodOverrides().isEmpty()) {
// 利用構造方法進行實例化
return BeanUtils.instantiateClass(constructorToUse);
}
else {
// 存在方法覆寫,利用 CGLIB 來完成實例化,需要依賴于 CGLIB 生成子類,這里就不展開了。
// tips: 因為如果不使用 CGLIB 的話,存在 override 的情況 JDK 并沒有提供相應的實例化支持
return instantiateWithMethodInjection(bd, beanName, owner);
}
}
b.bean 屬性注入
看完了 createBeanInstance(...) 方法,我們來看看 populateBean(...) 方法,該方法負責進行屬性設值,處理依賴。
// AbstractAutowireCapableBeanFactory 1203
protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw) {
// bean 實例的所有屬性都在這里了
PropertyValues pvs = mbd.getPropertyValues();
// 設置 bean 實例的屬性值
applyPropertyValues(beanName, mbd, bw, pvs);
c.initializeBean 初始化
屬性注入完成后,這一步其實就是處理各種回調了,這塊代碼比較簡單。
到此就完成了Spring中IoC容器一遍串講,已經(jīng)縮減了大量非關鍵代碼流程,體現(xiàn)出了主脈絡,但是關于創(chuàng)建 bean 這一塊還可以在下一篇文章中重點安排下,那一塊很精華值得深入閱讀,主鏈路的講解就先到這里。
最后講一下源碼閱讀方式,這里有兩種:一種是直接初始化一個Spring的工程,然后下載相應的依賴源碼,順著源碼一點點讀,非常簡便,缺點也很明顯不能在源碼基礎上做筆記+注釋。還有一種是直接從github上fork源碼分支到本地,然后在本地源碼基礎上加上關鍵的注釋,并且在關鍵的分支循環(huán)上都說明一下原因,雖然這樣的源碼閱讀稍微麻煩點,但是讀過以后記憶更深刻,而且可以把注釋筆記一并提交到自己git代碼倉庫里,時刻溫故知新。
主要參考目錄
1.Spring IOC 容器源碼分析
2.Spring 創(chuàng)建Bean流程
3.Spring的Bean生命周期,11 張高清流程圖及代碼,深度解析