IOC容器的繼承關(guān)系
BeanFactory是所有的bean工廠的父接口,bean工廠的繼承實(shí)現(xiàn)關(guān)系很是錯(cuò)綜復(fù)雜,其中的一條主線(xiàn)繼承關(guān)系就如下圖所示。BeanFactory中定義getBean()等基本方法。而HierachicalBeanFactrory主要是說(shuō)明Bean工廠是可以繼承實(shí)現(xiàn)的,所以其中定義了getParentBeanFactory()這個(gè)接口。而ConfigurableBeanFactory這個(gè)類(lèi)就是我們常用的bean工廠了。

ApplicationContext 是 Context 的頂級(jí)父類(lèi)??梢钥吹紸pplication其實(shí)是繼承自BeanFactory的。其就是對(duì)于BeanFactory環(huán)境的一個(gè)更好的整合。有了BeanFactory我們可以進(jìn)行編程式Ioc,那么有了ApplicationContext之后我們就可以使用聲明式Ioc了,Context對(duì)于各種類(lèi)型的配置文件的兼容整合大大提升了使用者的使用效率。
Context 作為 Spring 的 Ioc 容器,基本上整合了 Spring 的大部分功能,或者說(shuō)是大部分功能的基礎(chǔ)。

具體加載流程
一般開(kāi)始都是這樣一句代碼:
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:application.xml");
ClassPathXmlApplicationContext是ApplicationContext的實(shí)現(xiàn)類(lèi)。意思是加載xml文件創(chuàng)建一個(gè)ApplicationContext 的Spring 容器。
ApplicationContext 接口中的最后一個(gè)方法:AutowireCapableBeanFactory getAutowireCapableBeanFactory() throws IllegalStateException; 他的返回值是AutowireCapableBeanFactory,這個(gè)接口就是用來(lái)自動(dòng)裝配Bean的
然后我們回到上面的 new ClassPathXmlApplicationContext("classpath:application.xml")構(gòu)造方法。先看上面構(gòu)造方法那個(gè)源碼,setConfigLocations(configLocations);是根據(jù)提供的路徑,處理成配置文件數(shù)組(以分號(hào)、逗號(hào)、空格、tab、換行符分割),然后就到了重點(diǎn)的refresh()。
這個(gè)refresh()方法可以用來(lái)重新初始化ApplicationContext ,我們找到了這個(gè)方法的具體實(shí)現(xiàn),就找到了整個(gè)IOC容器啟動(dòng)的過(guò)程,下面貼出來(lái)這個(gè)方法的源碼:
@Override
public void refresh() throws BeansException, IllegalStateException {
// 來(lái)個(gè)鎖,不然 refresh() 還沒(méi)結(jié)束,你又來(lái)個(gè)啟動(dòng)或銷(xiāo)毀容器的操作,那不就亂套了嘛
synchronized (this.startupShutdownMonitor) {
// 準(zhǔn)備工作,記錄下容器的啟動(dòng)時(shí)間、標(biāo)記“已啟動(dòng)”狀態(tài)、處理配置文件中的占位符
prepareRefresh();
// 這步比較關(guān)鍵,這步完成后,配置文件就會(huì)解析成一個(gè)個(gè) Bean 定義,注冊(cè)到 BeanFactory 中,
// 當(dāng)然,這里說(shuō)的 Bean 還沒(méi)有初始化,只是配置信息都提取出來(lái)了,
// 注冊(cè)也只是將這些信息都保存到了注冊(cè)中心(說(shuō)到底核心是一個(gè) beanName-> beanDefinition 的 map)
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 設(shè)置 BeanFactory 的類(lèi)加載器,添加幾個(gè) BeanPostProcessor,手動(dòng)注冊(cè)幾個(gè)特殊的 bean
// 這塊待會(huì)會(huì)展開(kāi)說(shuō)
prepareBeanFactory(beanFactory);
try {
// 【這里需要知道 BeanFactoryPostProcessor 這個(gè)知識(shí)點(diǎn),Bean 如果實(shí)現(xiàn)了此接口,
// 那么在容器初始化以后,Spring 會(huì)負(fù)責(zé)調(diào)用里面的 postProcessBeanFactory 方法。】
// 這里是提供給子類(lèi)的擴(kuò)展點(diǎn),到這里的時(shí)候,所有的 Bean 都加載、注冊(cè)完成了,但是都還沒(méi)有初始化
// 具體的子類(lèi)可以在這步的時(shí)候添加一些特殊的 BeanFactoryPostProcessor 的實(shí)現(xiàn)類(lèi)或做點(diǎn)什么事
postProcessBeanFactory(beanFactory);
// 調(diào)用 BeanFactoryPostProcessor 各個(gè)實(shí)現(xiàn)類(lèi)的 postProcessBeanFactory(factory) 回調(diào)方法
invokeBeanFactoryPostProcessors(beanFactory);
// 注冊(cè) BeanPostProcessor 的實(shí)現(xiàn)類(lèi),注意看和 BeanFactoryPostProcessor 的區(qū)別
// 此接口兩個(gè)方法: postProcessBeforeInitialization 和 postProcessAfterInitialization
// 兩個(gè)方法分別在 Bean 初始化之前和初始化之后得到執(zhí)行。這里僅僅是注冊(cè),之后會(huì)看到回調(diào)這兩方法的時(shí)機(jī)
registerBeanPostProcessors(beanFactory);
// 初始化當(dāng)前 ApplicationContext 的 MessageSource,國(guó)際化這里就不展開(kāi)說(shuō)了,不然沒(méi)完沒(méi)了了
initMessageSource();
// 初始化當(dāng)前 ApplicationContext 的事件廣播器,這里也不展開(kāi)了
initApplicationEventMulticaster();
// 從方法名就可以知道,典型的模板方法(鉤子方法),不展開(kāi)說(shuō)
// 具體的子類(lèi)可以在這里初始化一些特殊的 Bean(在初始化 singleton beans 之前)
onRefresh();
// 注冊(cè)事件監(jiān)聽(tīng)器,監(jiān)聽(tīng)器需要實(shí)現(xiàn) ApplicationListener 接口。這也不是我們的重點(diǎn),過(guò)
registerListeners();
// 重點(diǎn),重點(diǎn),重點(diǎn)
// 初始化所有的 singleton beans
//(lazy-init 的除外)
finishBeanFactoryInitialization(beanFactory);
// 最后,廣播事件,ApplicationContext 初始化完成,不展開(kāi)
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.
// 銷(xiāo)毀已經(jīng)初始化的 singleton 的 Beans,以免有些 bean 會(huì)一直占用資源
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();
}
}
}
整個(gè)IOC容器的啟動(dòng)過(guò)程就在這個(gè)方法里,我們一個(gè)一個(gè)的來(lái)看。
1.加鎖
首先是一個(gè)synchronized加鎖,當(dāng)然要加鎖,不然你先調(diào)一次refresh()然后這次還沒(méi)處理完又調(diào)一次,就會(huì)亂套了。
2.prepareRefresh
接著往下看prepareRefresh();這個(gè)方法是做準(zhǔn)備工作的,記錄容器的啟動(dòng)時(shí)間、標(biāo)記“已啟動(dòng)”狀態(tài)、處理配置文件中的占位符。
部分源碼展示
/**
* 設(shè)置beanFactory類(lèi)加載器,這里的類(lèi)加載器就是上下文默認(rèn)的類(lèi)加載器
*/
beanFactory.setBeanClassLoader(getClassLoader());
設(shè)置bean表達(dá)式解釋器
添加bean表達(dá)式解釋器,為了能夠讓我們的beanFactory去解析bean表達(dá)式,模板默認(rèn)以前綴“#{”開(kāi)頭,以后綴“}”結(jié)尾
beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
3.注冊(cè)BeanDefinition到BeanFactory
下一步ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();這個(gè)就很重要了,這一步是把配置文件解析成一個(gè)個(gè)Bean,并且注冊(cè)到BeanFactory中,注意這里只是注冊(cè)進(jìn)去,并沒(méi)有初始化。
注冊(cè)實(shí)現(xiàn)原理
BeanDefinition (Bean定義)
ioc 實(shí)現(xiàn)中 我們?cè)趚ml 中描述的Bean信息最后 都將保存至BeanDefinition (定義)對(duì)象中,其中xml bean與BeanDefinition 程一對(duì)一的關(guān)系。

由此可見(jiàn),xml bean中設(shè)置的屬性最后都會(huì)體現(xiàn)在BeanDefinition中。如:

BeanDefinitionRegistry(Bean注冊(cè)器)
在上表中我們并沒(méi)有看到 xml bean 中的 id 和name屬性沒(méi)有體現(xiàn)在定義中,原因是ID 其作為當(dāng)前Bean的存儲(chǔ)key注冊(cè)到了BeanDefinitionRegistry 注冊(cè)器中。name 作為別名key 注冊(cè)到了 AliasRegistry 注冊(cè)中心。其最后都是指向其對(duì)應(yīng)的BeanDefinition。
BeanDefinitionReader(Bean定義讀?。?/strong>
BeanDefinition 中存儲(chǔ)了Xml Bean信息,而B(niǎo)eanDefinitionRegister 基于ID和name 保存了Bean的定義。接下的是從xml Bean到BeanDefinition 然后在注冊(cè)至BeanDefinitionRegister 整個(gè)過(guò)程。

上圖中可以看出Bean的定義是由BeanDefinitionReader 從xml 中讀取配置并構(gòu)建出 BeanDefinition,然后在基于別名注冊(cè)BeanDefinitionRegister中。
ps:還有一點(diǎn)細(xì)節(jié):加載解析的過(guò)程是先由XmlBeanDefinitionReader加載Bean定義資源,然后DocumentLoader將Bean定義資源轉(zhuǎn)換為Document對(duì)象。XmlBeanDefinitionReader再解析載入的Bean定義資源文件
最后由DefaultBeanDefinitionDocumentReader對(duì)Bean定義的Document對(duì)象解析。
4.prepareBeanFactory
4.然后是prepareBeanFactory(beanFactory);這個(gè)方法的作用是:設(shè)置 BeanFactory 的類(lèi)加載器,添加幾個(gè) BeanPostProcessor,手動(dòng)注冊(cè)幾個(gè)特殊的 bean,這里都是spring里面的特殊處理。
5.postProcessBeanFactory
5.postProcessBeanFactory(beanFactory);方法是提供給子類(lèi)的擴(kuò)展點(diǎn),到這里的時(shí)候,所有的 Bean 都加載、注冊(cè)完成了,但是都還沒(méi)有初始化,具體的子類(lèi)可以在這步的時(shí)候添加一些特殊的 。BeanFactoryPostProcessor 的實(shí)現(xiàn)類(lèi),來(lái)完成一些其他的操作。
BeanPostProcessor接口作用:
如果我們想在Spring容器中完成bean實(shí)例化、配置以及其他初始化方法前后要添加一些自己邏輯處理。我們需要定義一個(gè)或多個(gè)BeanPostProcessor接口實(shí)現(xiàn)類(lèi),然后注冊(cè)到Spring IoC容器中。
詳情參考:BeanPostProcessor接口作用
6.執(zhí)行容器中實(shí)現(xiàn)的BeanFactoryPostProcessor的子類(lèi)(如果有的話(huà))
接下來(lái)是invokeBeanFactoryPostProcessors(beanFactory);這個(gè)方法是調(diào)用 BeanFactoryPostProcessor 各個(gè)實(shí)現(xiàn)類(lèi)的 postProcessBeanFactory(factory) 方法;
7.后置處理器的實(shí)現(xiàn)BeanPostProcessors
然后是registerBeanPostProcessors(beanFactory);這個(gè)方法注冊(cè) BeanPostProcessor 的實(shí)現(xiàn)類(lèi),和上面的BeanFactoryPostProcessor 是有區(qū)別的,這個(gè)方法調(diào)用的其實(shí)是PostProcessorRegistrationDelegate類(lèi)的registerBeanPostProcessors方法;這個(gè)類(lèi)里面有個(gè)內(nèi)部類(lèi)BeanPostProcessorChecker,BeanPostProcessorChecker里面有兩個(gè)方法postProcessBeforeInitialization和postProcessAfterInitialization,這兩個(gè)方法分別在 Bean 初始化之前和初始化之后得到執(zhí)行。
這里就是bean的后置處理器的執(zhí)行原理。
詳情參考:BeanPostProcessor
8.國(guó)際化
initMessageSource();方法是初始化當(dāng)前 ApplicationContext 的 MessageSource,國(guó)際化處理。
9.初始化事件廣播器
initApplicationEventMulticaster();方法初始化當(dāng)前 ApplicationContext 的事件廣播器。
10.初始化一些特殊的 Bean
onRefresh();方法初始化一些特殊的 Bean(在初始化 singleton beans 之前)
11.注冊(cè)事件監(jiān)聽(tīng)器
registerListeners();方法注冊(cè)事件監(jiān)聽(tīng)器,監(jiān)聽(tīng)器需要實(shí)現(xiàn) ApplicationListener 接口
12.初始化bean
重點(diǎn)到了:finishBeanFactoryInitialization(beanFactory);初始化所有的 singleton beans(單例bean),懶加載(non-lazy-init)的除外(spring默認(rèn)不是懶加載,如果設(shè)定了懶加載,則bean的初始化由getbean方法觸發(fā))。
我們來(lái)看初始化bean的流程圖

從調(diào)用過(guò)程可以總結(jié)出以下幾點(diǎn):
1.調(diào)用BeanFactory.getBean() 會(huì)觸發(fā)Bean的實(shí)例化。
2.DefaultSingletonBeanRegistry 中緩存了單例Bean
3.Bean的創(chuàng)建與初始化是由AbstractAutowireCapableBeanFactory 完成的。
13廣播事件,告訴上下文,容器已經(jīng)創(chuàng)建好,隨時(shí)可以調(diào)用
finishRefresh();方法是最后一步,廣播事件,ApplicationContext 初始化完成。
Ioc容器的加載過(guò)程簡(jiǎn)單概括:
1.刷新預(yù)處理
2.將配置信息解析,注冊(cè)到BeanFactory
3.設(shè)置bean的類(lèi)加載器
4.如果有第三方想再bean加載注冊(cè)完成后,初始化前做點(diǎn)什么(例如修改屬性的值,修改bean的scope為單例或者多例。),提供了相應(yīng)的模板方法,后面還調(diào)用了這個(gè)方法的實(shí)現(xiàn),并且把這些個(gè)實(shí)現(xiàn)類(lèi)注冊(cè)到對(duì)應(yīng)的容器中
5.初始化當(dāng)前的事件廣播器
6.初始化所有的bean。(懶加載不執(zhí)行這一步)
7.廣播applicationcontext初始化完成。
ps:BeanFactory 與 ApplicationContext區(qū)別
BeanFactory 看下去可以去做IOC當(dāng)中的大部分事情,為什么還要去定義一個(gè)ApplicationContext 呢?
ApplicationContext 它由BeanFactory接口派生而來(lái),因而提供了BeanFactory所有的功能。除此之外context包還提供了以下的功能:
1.MessageSource, 提供國(guó)際化的消息訪問(wèn)
2.資源訪問(wèn),如URL和文件
3.事件傳播,實(shí)現(xiàn)了ApplicationListener接口的bean
4.載入多個(gè)(有繼承關(guān)系)上下文 ,使得每一個(gè)上下文都專(zhuān)注于一個(gè)特定的層次,比如應(yīng)用的web層
參考1:Spring IOC加載全過(guò)程
參考2:Spring深入 2.IOC設(shè)計(jì)原理與實(shí)現(xiàn)
參考3:spring加載流程之prepareBeanFactory(beanFactory)
參考4:Spring中的后置處理器BeanPostProcessor講解
參考5:Spring中BeanFactoryPostProcessor和BeanPostProcessor區(qū)別