前言
上周線上項目出了一個bug,使用WebMvcConfigurer和WebMvcConfigurationSupport不能同時使用,要不然WebMvcConfigurer能掃描到容器中,但是他的方法不能執行。
只有搞懂了spring的源碼流程,才能對這個問題進行整體的把握。
ApplicationContext簡介
通過debug的方式對spirng源碼進行一步一步的解讀,spring的核心之一就是IOC容器,這是一個抽象的概念,對應IOC,做過spirng開發的想必都有所耳聞,但是對於他是什么大部分初級程序員是不明朗的。
IOC體現在spring中就是ApplicationContext,這是最重要的接口,spirng中有眾多的類實現了這個接口,不同的ApplicationContext在不同的應用場景使用。
AnnotationConfigApplicationContext是基於注解的方式啟動容器,ClassPathXmlApplicationContext是基於xml配置的方式啟動容器,其他還有許多的方式啟動容器,雖然多,但是能夠見名知意,名字都是**ApplicationContext。

類名有個簡單的印象就行,如果都看一遍太枯燥了,筆者也不推薦這樣做。
Beanfactory簡介
BeanFactory我的理解就是IOC容器中的一些工具方法,這是我淺顯的理解,下圖是BeanFactory 的所有方法,ApplicationContext繼承了這個接口。

啟動過程
通過debug的方式一步步深挖spring源碼,一定要自己debug要不然很累!一定要自己debug要不然很累!一定要自己debug要不然很累!重要事情說三遍。
先通過一個簡單的樣例,看下spring-ico的一個簡單使用。這個方法的作用就是new了一個ApplicationContext傳入一個定義的bean,然后通過getBeanDefinitionNames()獲取到它的容器中所有的bean。


點進去ApplicationContext的構造方法,會發現它調用了一個refresh()方法,這個方法是spring-ico最核心的方法,IOC初始化、注冊bean等等一系列方法都是這這里完成的。
值得一提的是,springboot的run方法一步步點進去調用的還是這個refresh方法,看到這相信大家對於spirng和springboot的關系有了一個模糊的認識。

透過現象看本質,其實springboot的核心啟動方法還是調用了spring的run方法,只是在這個方法的前后又做了一些啟動的事,增強了spring而已。
書歸正傳,讓我們重新回到refresh方法中一步步的解讀。在refresh上面打上一個斷點,一步一步看每一個方法都做了什么事。

高能預警:下面是一段超長的源碼分析,可能引起不適,但是對於技術的提高也是顯著的。
@Override
public void refresh() throws BeansException, IllegalStateException {
// 加鎖,避免 refresh() 啟動和銷毀容器混亂this.startupShutdownMonito該鎖為當前對象。
synchronized (this.startupShutdownMonitor) {
// 准備工作,記錄下容器的啟動時間、標記“已啟動”狀態、處理配置文件中的占位符
prepareRefresh();
// 這步比較關鍵,這步完成后,配置文件就會解析成一個個 Bean 定義,注冊到 BeanFactory 中,
// 當然,這里說的 Bean 還沒有初始化,只是配置信息都提取出來了,
// 注冊也只是將這些信息都保存到了注冊中心(說到底核心是一個 beanName-> beanDefinition 的 map)
**ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();**
// 設置 BeanFactory 的類加載器,添加幾個 BeanPostProcessor,手動注冊幾個特殊的 bean
// 這塊待會會展開說
prepareBeanFactory(beanFactory);
try {
// 【這里需要知道 BeanFactoryPostProcessor 這個知識點,Bean 如果實現了此接口,
// 那么在容器初始化以后,Spring 會負責調用里面的 postProcessBeanFactory 方法。】
// 這里是提供給子類的擴展點,到這里的時候,所有的 Bean 都加載、注冊完成了,但是都還沒有初始化
// 具體的子類可以在這步的時候添加一些特殊的 BeanFactoryPostProcessor 的實現類或做點什么事
postProcessBeanFactory(beanFactory);
// 調用 BeanFactoryPostProcessor 各個實現類的 postProcessBeanFactory(factory) 方法
invokeBeanFactoryPostProcessors(beanFactory);
// 注冊 BeanPostProcessor 的實現類,注意看和 BeanFactoryPostProcessor 的區別
// 此接口兩個方法: postProcessBeforeInitialization 和 postProcessAfterInitialization
// 兩個方法分別在 Bean 初始化之前和初始化之后得到執行。注意,到這里 Bean 還沒初始化
registerBeanPostProcessors(beanFactory);
// 國際化
initMessageSource();
// 初始化當前 ApplicationContext 的事件廣播器
initApplicationEventMulticaster();
// 從方法名就可以知道,典型的模板方法(鈎子方法),
// 具體的子類可以在這里初始化一些特殊的 Bean(在初始化 singleton beans 之前)
onRefresh();
// 注冊事件監聽器,監聽器需要實現 ApplicationListener 接口。
registerListeners();
// 初始化所有的 singleton beans
//(lazy-init 的除外)
finishBeanFactoryInitialization(beanFactory);
// 最后,廣播事件,ApplicationContext 初始化完成
finishRefresh();
}
// Destroy already created singletons to avoid dangling resources.
// 銷毀已經初始化的 singleton 的 Beans,以免有些 bean 會一直占用資源
destroyBeans();
// 把異常往外拋
throw ex;
}
finally {
// Reset common introspection caches in Spring's core, since we
// 重置緩存
resetCommonCaches();
}
}
}
以上就是refresh()方法概述,如果全部展開來講的話會很長很長,接下來會分很多文章來解讀每一個方法的源碼,但是讀者要對它的所有方法做到心中有數。
spring與其他框架的整合,都蘊含在這些方面中,充分利用了spring的擴展性。
總結
在花了一天時間后,這篇文章終於算是基本寫完了,應該透過現象看本質,去理解 Spring 寫得好的地方,去理解它的設計思想。
充分解讀spring代碼量真的比較大,分支旁路眾多。以后會逐步拆解它的每一個問題,敬請期待吧。
