<a></a>初始化容器
- 服務(wù)器容器根據(jù)配置文件(Tomcat:web.xml)加載ContextInitialListener事件:
ContextLoaderListener.contextInitialized()
; - 嘗試獲得parentContext;
- 根據(jù)parentContext [初始化ApplicationContext](#Initial ApplicationContext);
- 將
ApplicationRoot
為key对人,將context注冊(cè)到servletContext中; - 如果當(dāng)前線程的ClassLoader為ContextClassLoader,則將context設(shè)置為currentContext;否則將context設(shè)置為perThreadContext;
<a name='Initial ApplicationContext'>初始化ApplicationContext</a>
- 通過(guò)
BeanUtil.instantiateClass()
來(lái)創(chuàng)建ConfigurableWebApplicationContext曲饱; - 設(shè)置context的id洲炊、parent梅割、servletContext等屬性(不曉得Id有什么用乃坤,代碼還費(fèi)了好幾行獲得best possible id??);
- 調(diào)用
ctx.refresh()
方法[構(gòu)建Spring容器](#start up Spring)構(gòu)建Spring容器.
通過(guò)refresh方式初始化容器而不是init的方式陶贼,而且refresh中有通過(guò)beanFactory.getBean方式獲取的對(duì)象悦荒,初始化階段BeanFactory中是沒(méi)有BeanDefinition的春贸,因此這里我懷疑和tomcat的熱部署有關(guān)系混萝。
<a name='start up Spring'>構(gòu)建Spring容器</a>
- 根據(jù)信號(hào)
startupShutdownMonitor
來(lái)作同步,在同步代碼塊中進(jìn)行refresh操作;
Spring注釋對(duì)startupShutdownMonitor有如下解釋:
Synchronization monitor for the "refresh" and "destroy".
即destroy方法必須等refresh方法執(zhí)行完之后才能被調(diào)用;
-
prepareRefresh()
:準(zhǔn)備刷新萍恕,這里有個(gè)同步設(shè)置變量active逸嘀,沒(méi)看懂啥意思; -
obtainRefreshBeanFactory()
:[初始化](#init beanFactory)并獲取BeanFactory; -
prepareBeanFactory()
:初始化BeanFactory的依賴允粤,包括ignoreDependency和硬代碼registerDependency;Ignore掉的依賴通常是由別的方式進(jìn)行注入崭倘,比如BeanFactory對(duì)象可以由BeanFactoryAware方式注入;獲取并維護(hù)系統(tǒng)變量和環(huán)境變量 -
invokeBeanFactoryPostProcessor()
:根據(jù)BeanFactory是否為BeanDefinitionRegistry來(lái)調(diào)用BeanFactoryPostProcessor,再根據(jù)priority类垫、order司光、nonOrder的順序調(diào)用BeanPostProcessor。在服務(wù)器初始化階段并沒(méi)有注冊(cè)BeanFactoryPostProcessor悉患,也許在熱部署階段會(huì)執(zhí)行吧残家;也就是說(shuō),BeanFactoryPostProcessor是在BeanFactory初始化之后Bean對(duì)象初始化前執(zhí)行的 -
registerBeanPostProcessor()
:根據(jù)BeanFactory.getBeanNamesForType()
獲取BeanPostProcessor售躁,然后以Priority坞淮、Order茴晋、NonOrder的順序注冊(cè)到BeanPostProcessorList中。BeanPostProcessorList為ArrayList回窘,因此執(zhí)行順序?yàn)椋篜riority>Order>NonOrder诺擅; -
initMessageSource()
:獲取MessageSource對(duì)象,默認(rèn)為DelegatingMessageSource; - 接下來(lái)是注冊(cè)廣播事件監(jiān)聽(tīng)器啡直、調(diào)用子類的onRefresh方法烁涌、注冊(cè)應(yīng)用監(jiān)聽(tīng)器;
-
finishBeanFactoryInitialization()
:初始化所有not-lazy-init Bean酒觅。也是SpringCore的核心代碼烹玉; -
finishRefresh
:觸發(fā)加載完成事件;
<a name='init beanFactory'>初始化BeanFactory</a>
- 清空已加載的Bean阐滩;
- 創(chuàng)建一個(gè)內(nèi)部BeanFactory;
- 自定義BeanFactory配置:setAllowBeanDefinitionOverriding县忌、setAllowEagerClassLoading掂榔、setAllowCircularReferences、setAllowRawInjectionDespiteWrapping
-
loadBeanDefinitions()
:遍歷Resources中的Xml定義的bean加載至BeanDefinition症杏;
<a name='loadBeanDefinition'>Bean加載</a>
- 根據(jù)Resource生成Document對(duì)象装获;根據(jù)Document的Element的nodeName屬性來(lái)處理Bean:
- 如果nodeName為Import,則執(zhí)行
importBeanDefinitionResource
操作加載import-resource定義的bean: - 如果nodeName為Alias厉颤,則將BeanName與Alias關(guān)聯(lián)注冊(cè)穴豫;
- 如果nodeName為Bean,則根據(jù)屬性解析Element生成BeanHolder逼友,將BeanName與BeanDefinition注冊(cè)到BeanDefinitions緩存中;
- 如果nodeName為Beans,則跳至1.處理Beans中的Bean精肃;
- 如果nodeName為Import,則執(zhí)行
<a name='spring-core'>核心代碼</a>
- 1.
finishBeanFactoryInitialization
->preInstantiateSingletons()
:同步獲取緩存中的beanDefinitionNames
,放到局部變量中; - 遍歷beanDefinitionName,調(diào)用[getBean()](#get bean)初始化Bean;
<a name = 'get bean'>getBean()</a>
- 首先嘗試從singletonObjects帜乞、earlySingletonObjects的緩存中獲取對(duì)象;
- 如果對(duì)象不為空司抱,則調(diào)用
getObjectForBeanInstance()
方法通過(guò)FactoryBean或者對(duì)象本身的方式獲得Bean對(duì)象; - 如果對(duì)象不為空,則嘗試在ParentBeanFactory中獲得對(duì)象黎烈,并返回习柠;
- 如果ParentBeanFactory對(duì)象中沒(méi)有獲得Bean對(duì)象,則讀取BeanDefinistions緩存中獲得該Bean的Definition對(duì)象照棋;
- 拿到BeanDefinition對(duì)象后资溃,遍歷該對(duì)象的dependsOn屬性,并將該BeanName與DependsOn的對(duì)象Name注冊(cè)dependentBeanMap中烈炭,然后調(diào)用[getBean()](#get bean)來(lái)實(shí)例化DependsOn的對(duì)象溶锭。這里會(huì)根據(jù)dependentBeanMap來(lái)檢查是否存在循環(huán)依賴,(Spring對(duì)Bean屬性之間的循壞依賴是有解決方案的梳庆,不清楚這里的循壞依賴為什么會(huì)直接拋出異常)暖途;
- 實(shí)例化DependsOn對(duì)象后卑惜,再根據(jù)Bean的Scope屬性創(chuàng)建對(duì)象,Singleton方式和prototype方式的區(qū)別在于Singleton對(duì)象在創(chuàng)建的時(shí)候首先會(huì)在緩存中取對(duì)象驻售,如果不存在再createBean()創(chuàng)建一個(gè)新的對(duì)象放到singletonObjects和earlySingletonObjects中露久,而prototype類型的則不不會(huì)在緩存中取對(duì)象,直接創(chuàng)建新對(duì)象.
-
getObjectForBeanInstance()
:拿到Bean對(duì)象之后欺栗,確定Bean是否為FactoryBean毫痕,如果是則需要通過(guò)FactoryBean的方式獲取bean,否則直接返回bean.
<a name='createBean'>createBean()</a>
- 在初始化前迟几,首先調(diào)用
resolveBeanClass()
確保beanClass已經(jīng)加載到ClassLoader里面消请;這里會(huì)去看BeanDefinition中是否有指定的class,如果沒(méi)有类腮,則會(huì)調(diào)用ClassUtils.forName()
在ClassLoader容器中加載class臊泰; - 確保class已經(jīng)加載完成之后,執(zhí)行
resolveBeforeInstantiation()
蚜枢,嘗試通過(guò)InstantiationAwareBeanPostProcessor
來(lái)創(chuàng)建Bean缸逃,如果Bean創(chuàng)建成功,則調(diào)用applyBeanPostProcessorsAfterInitialization()
應(yīng)用Bean后處理器厂抽,并返回Bean對(duì)象需频;(InstantiationAwareBeanPostProcessor
這個(gè)里面雖然可以返回null,但是返回null之后筷凤,Spring容器會(huì)認(rèn)為沒(méi)有創(chuàng)建bean昭殉,重新創(chuàng)建bean) - 如果
InstantiationAwareBeanPostProcessor
返回null,調(diào)用doCreateBean()真正的創(chuàng)建Bean對(duì)象.(os:創(chuàng)建個(gè)對(duì)象前戲真長(zhǎng)??)
<a name='doCreateBean'>doCreateBean()</a>
- 通過(guò)
createBeanInstance()
創(chuàng)建Bean實(shí)例。該方法首先在resolvedConstructor的一系列變量中找到緩存的Constructor藐守,否則找到一個(gè)FastConstructor(找最合適的過(guò)程比較冗長(zhǎng)挪丢,這里省略這么多字),再根據(jù)是否有OverrideMethod吗伤,來(lái)選擇通過(guò)Reflect的形式還是CGlib的形式創(chuàng)建對(duì)象吃靠; - Bean實(shí)例化出來(lái)之后,調(diào)用
applyMergedBeanDefinitionPostProcessors()
來(lái)執(zhí)行BeanPostProcessor足淆; - 這時(shí)候?qū)傩赃€是空的巢块,在注入屬性時(shí)會(huì)發(fā)生循環(huán)依賴的問(wèn)題,因此這里會(huì)判斷是否允許循環(huán)依賴巧号,如果允許的話將bean的引用通過(guò)
ObejctFactory
工廠的方式暴露出去族奢; -
populateBean()
,遍歷并且注入依賴丹鸿。 -
initializeBean()
越走,調(diào)用Bean的初始化方法,init啦,afterPropertiesSet啦廊敌。
額外補(bǔ)充:實(shí)例Bean是什么時(shí)候變成Proxy的呢铜跑?
通過(guò)doCreateBean()的步驟1.出來(lái)的實(shí)例這個(gè)時(shí)候還是對(duì)象本身,而Spring暴露出來(lái)的Bean又都是以代理形式出現(xiàn)的骡澈,那么Spring是什么時(shí)候?qū)?shí)例進(jìn)行代理wrap的呢锅纺,通過(guò)Debug看到在applyMergedBeanDefinitionPostProcessors()
階段,
AbstractAutoProxyCreator以BeanPostProcessor的方式對(duì)實(shí)例出來(lái)的Bean進(jìn)行AutoProxy肋殴,通過(guò)判斷該實(shí)例的Class對(duì)象是否有Interfaces囤锉,如果有則通過(guò)JDK Dynamic的方式代理,否則使用CGlib.