??springboot
在啟動(dòng)的時(shí)候,會(huì)調(diào)用run
方法,創(chuàng)建環(huán)境設(shè)置spring容器,其中包含refresh
方法,完成配置類解析,各種beanFactoryPostProcess
和beanPostProcessor
注冊,web內(nèi)置容器構(gòu)造,國際化配置初始化等,refresh
調(diào)用了父類AbstractApplicationContext
的refresh
方法如下。
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 準(zhǔn)備,記錄容器的啟動(dòng)時(shí)間startupDate, 標(biāo)記容器為激活,初始化上下文環(huán)境如文件路徑信息,驗(yàn)證必填屬性是否填寫
prepareRefresh();
// 這步比較重要(解析),告訴子類去刷新bean工廠,這步完成后配置文件就解析成一個(gè)個(gè)bean定義,注冊到BeanFactory(但是未被初始化,僅將信息寫到了beanDefination的map中)
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 設(shè)置beanFactory類加載器,添加多個(gè)beanPostProcesser
prepareBeanFactory(beanFactory);
try {
// 允許子類上下文中對beanFactory做后期處理
postProcessBeanFactory(beanFactory);
// 調(diào)用BeanFactoryPostProcessor各個(gè)實(shí)現(xiàn)類的方法
invokeBeanFactoryPostProcessors(beanFactory);
// 注冊 BeanPostProcessor 的實(shí)現(xiàn)類,注意看和 BeanFactoryPostProcessor 的區(qū)別
// 此接口兩個(gè)方法: postProcessBeforeInitialization 和 postProcessAfterInitialization
// 兩個(gè)方法分別在 Bean 初始化之前和初始化之后得到執(zhí)行。注意,到這里 Bean 還沒初始化
registerBeanPostProcessors(beanFactory);
//初始化ApplicationContext的MessageSource
initMessageSource();
//初始化ApplicationContext事件廣播器
initApplicationEventMulticaster();
// 初始化子類特殊bean(鉤子方法)
onRefresh();
// 注冊事件監(jiān)聽器
registerListeners();
// 初始化所有singleton bean 重點(diǎn)!!重點(diǎn)!!
finishBeanFactoryInitialization(beanFactory);
// 廣播事件,ApplicationContext初始化完成
finishRefresh();
} catch (BeansException ex) {
....................
}
1. prepareRefresh()
??在rehresh
之前做的準(zhǔn)備工作,一是設(shè)置spring啟動(dòng)事件,開啟活躍狀態(tài);二是初始化屬性源信息;三是驗(yàn)證必要屬性。
1.1 initPropertySources()
??在應(yīng)用啟動(dòng)之前替換一些屬性占位符,這個(gè)方法再Spring的對象中一般都沒有實(shí)現(xiàn),應(yīng)該是用來方便我們后期擴(kuò)展使用的方法。
1.2 validateRequiredProperties()
??Environment
類的方法驗(yàn)證必須的屬性是否正確。
2. obtainFreshBeanFactory();
??獲取新的beanFactory
,銷毀原有beanFactory
、為每個(gè)bean
生成BeanDefinition
等
??obtainFreshBeanFactory
方法從字面的意思看獲取新的Bean工廠,實(shí)際上這是一個(gè)過程,一個(gè)加載Xml資源并解析,根據(jù)解析結(jié)果組裝BeanDefinitions
,然后初始化BeanFactory
的過程。如下圖跳入方法源碼中
2.1 refreshBeanFactory()
??refreshBeanFactory
是具體的刷新BeanFactory
,負(fù)責(zé)這個(gè)工作做在類AbstractRefreshableApplicationContext
中,顧名思義這是專門用來刷新的。
詳細(xì)說明:
- 首先判斷,是否存在
BeanFactory
,如果存在容器beanFactory
,則先銷毀所有的bean,然后關(guān)閉beanFactory
; -
DefaultListableBeanFactory beanFactory = createBeanFactory();
創(chuàng)建初始容器beanFactory
,此處創(chuàng)建的是DefaultListableBaenFactory
,是最重要的beanFactory
,即初始化容器;spring注冊&加載bean的基本容器;
image -
customizeBeanFactory(beanFactory);
根據(jù)AbstractRefreshableApplicationContext
類的屬性為Beanfactory
設(shè)置屬性值。
image
allowBeanDefinitionOverriding:屬性是指是否允對一個(gè)名字相同但definition不同進(jìn)行重新注冊,默認(rèn)是true。 allowCircularReferences屬性是指是否允許Bean之間循環(huán)引用,默認(rèn)是true
默認(rèn)兩個(gè)屬性都為空,可擴(kuò)展的,可以自己設(shè)置屬性,方法就是繼承ClassPathXmlApplicationContext
并復(fù)寫customizeBeanFactory
方法為兩個(gè)屬性設(shè)置值即可。 -
loadBeanDefinitions(beanFactory);
將BeanDenifition
注冊到bean
工廠
[圖片上傳失敗...(image-e0509-1560845367203)]查看最后一個(gè)方法:
loadBeanDefinitions(beanDefinitionReader);
image
例如:applicationContext.xml
不是在calsspath
下了,只有Resource
,那怎么辦,直接傳遞進(jìn)來即可,繼承ClassPathXmlApplicationContext
類重寫getConfigResources
方法,返回Resource
即可。
3. prepareBeanFactory();
??在ApplicationContext
刷新獲取beanFactory
之后,開始準(zhǔn)備context
使用的beanFactory
。這一步相對比較簡單,就是配置beanFacotry
的特性
-
beanFactory.setBeanClassLoader(getClassLoader());
設(shè)置類加載器;設(shè)置BeanFactory
的BeanClassLoader
,如果存在,則直接使用之前的那個(gè),否則,初始化一個(gè)新的ClassLoader
;image beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
設(shè)置BeanExpressionResolver
表達(dá)式解析器,主要用來解析EL表達(dá)式;Bean初始化完成后填充屬性時(shí)會(huì)用到beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
設(shè)置屬性注冊解析器PropertyEditor
;這個(gè)主要是對某些注入的Bean的一些屬性的支持;beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor (this));
此處添加了一個(gè)BeanPostProcessor實(shí)現(xiàn):ApplicationContextAwareProcessor,它是用來處理并回調(diào)實(shí)現(xiàn)了各種Aware接口的Bean,比如獲取ApplicationContext的ApplicationContextAware接口。添加BeanPostProcessor
(Bean后置處理器ApplicationContextAwareProcessor
),當(dāng)bean被這個(gè)工廠創(chuàng)建的時(shí)候會(huì)用到PostProcessor
, 在beanfactory
中存儲了beanPostProcessors
的列表,在生效的時(shí)候,列表中的PostProcessor
都會(huì)執(zhí)行。 在bean初始化之前,調(diào)用ApplicationContextAwareProcessor
的postProcessBeforeInitialization
處理所有的Aware
接口,進(jìn)行如下操作:
// 如果bean實(shí)現(xiàn)了EmbeddedValueResolverAware接口,調(diào)用bean.setEmbeddedValueResolver
// 如果bean實(shí)現(xiàn)了ResourceLoaderAware接口,調(diào)用bean.setResourceLoader
// 如果bean實(shí)現(xiàn)了ApplicationEventPublisherAware接口,調(diào)用bean.setApplicationEventPublisher
// 如果bean實(shí)現(xiàn)了MessageSourceAware接口,調(diào)用bean.setMessageSource
// 如果bean實(shí)現(xiàn)了ApplicationContextAware接口,調(diào)用bean.setApplicationContext
-
beanFactory.ignoreDependencyInterface()
指定的接口不會(huì)被自動(dòng)注入進(jìn)去。 -
beanFactory.registerResolvableDependency()
設(shè)置幾個(gè)自動(dòng)裝配規(guī)則,例如BeanFactory則注入beanFactory ResourceLoader,ApplicationEventPublisher,ApplicationContext注入當(dāng)前對象
image -
beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)
如果當(dāng)前BeanFactory
包含loadTimeWeaver
Bean,說明存在類加載期織入AspectJ
,則把當(dāng)前BeanFactory
交給類加載期BeanPostProcessor
實(shí)現(xiàn)類LoadTimeWeaverAwareProcessor
來處理,從而實(shí)現(xiàn)類加載期織入AspectJ
的目的。
image - 注冊當(dāng)前容器環(huán)境
environment
組件Bean
[圖片上傳失敗...(image-edc8e7-1560845367203)] - 注冊系統(tǒng)配置
systemProperties
組件Bean
image - 注冊系統(tǒng)環(huán)境
systemEnvironment
組件Bean
image
??總結(jié):
(1)設(shè)置類加載器 (2)設(shè)置EL表達(dá)式解析器(bean創(chuàng)建完成填充屬性時(shí)使用)和屬性注冊解析器 (3)利用beanPostProcessor的特性給各種Aware接口的實(shí)現(xiàn)類注入ApplicationContext中對應(yīng)的屬性; (4)設(shè)置各種Aware接口的實(shí)現(xiàn)類為忽略自動(dòng)裝配 (5)設(shè)置自動(dòng)裝配類(BeanFactory,ResourceLoader,ApplicationEventPublisher,ApplicationContext) (6)如果BeanFactory中存在loadTimeWeaver的bean,那么需要添加動(dòng)態(tài)織入功能 (7).注冊各種可用組件(environment,systemProperties,systemEnvironment)
4.postProcessBeanFactory()
??bean工廠的bean屬性處理容器,說通俗一些就是可以管理我們的bean工廠內(nèi)所有的beandefinition
(未實(shí)例化)數(shù)據(jù);
??postProcessBeanFactory
后處理beanFactory
。時(shí)機(jī)是在所有的beanDenifition
加載完成之后,bean實(shí)例化之前執(zhí)行。
??比如,在beanfactory
加載完成所有的bean后,想修改其中某個(gè)bean的定義,或者對beanFactory
做一些其他的配置,就可以用此方法。在系列文章中,可以實(shí)現(xiàn)ClassPathXmlApplicationContext
類并重寫postProcessBeanFactory
即可。
默認(rèn)情況下此方法是空的。需要子類去實(shí)現(xiàn)
注意:
BeanFactoryPostProcessor的主要作用是讓你能接觸到bean definitions,對bean definitions進(jìn)行一定hack,但是也僅此而已了。絕對不允許在BeanFactoryPostProcessor中觸發(fā)到bean的實(shí)例化!
舉例:
@Component
public class PrematureBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
Map<String, BBean> map = beanFactory.getBeansOfType(BBean.class);
for (BBean bBean : map.values()) {
assert bBean.getABean() == null;
}
}
}
@Component("bBean")
public class BBean {
@Autowired
private ABean aBean;
public ABean getABean() {
return aBean;
}
}
@Component
public class ABean {
private String name = "a";
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
??在運(yùn)行后,BBean中被期待注入的ABean最終為null。這是為啥呢?postProcessBeanFactory(beanFactory);
首先invoke了容器中的BeanFactoryPostProcessor
實(shí)現(xiàn)類,其中當(dāng)然就包括PrematureBeanFactoryPostProcessor
,此時(shí)通過beanFactory.getBeansOfType
觸發(fā)了bean提前實(shí)例化。按理說,bean提前實(shí)例化也應(yīng)該沒問題的,aBean也應(yīng)該是能夠被注入的呀!那為啥最終不是這個(gè)結(jié)果呢?
??從源碼可知:
@AutoWired
起作用依賴AutowiredAnnotationBeanPostProcessor
;
@Resource
依賴CommonAnnotationBeanPostProcessor
,這倆都是BeanPostProcessor
的實(shí)現(xiàn)。
??那BeanPostProcessors
在何處被spring invoke呢?
參見refresh()
方法registerBeanPostProcessors(beanFactory);
在postProcessBeanFactory(beanFactory);
后面被調(diào)用;
??也就是說BBean被觸發(fā)提前初始化的時(shí)候,AutowiredAnnotationBeanPostProcessor
還沒有被注冊自然也不會(huì)被執(zhí)行到,自然ABean=null
。
5.invokeBeanFactoryPostProcessors(beanFactory);
??實(shí)例化Factory之前預(yù)處理部分
??invokeBeanFactoryPostProcessors
方法主要用于處理 BeanFactoryPostProcessor
接口。BeanFactoryPostProcessor
接口是 Spring 初始化 Bean 時(shí)對外暴露的擴(kuò)展點(diǎn),Spring IoC 容器允許 BeanFactoryPostProcessor
在容器實(shí)例化任何 Bean 之前讀取Bean 的定義,并可以修改它。
??可以理解為,初始化我們自定義的BeanFactoryPostProcessor
;
postProcessBeanFactory
用于在標(biāo)準(zhǔn)的初始化完成后修改容器上下文中的beanFactory
。所有bean定義將被加載,但是它們將暫時(shí)不被實(shí)例化,這允許覆蓋,甚至添加一些屬性到延遲初始化的bean上。也就是說,允許我們開發(fā)者自定義的去修改BeanFactory
中的內(nèi)容,這也是符合“spring”的開閉原則。invokeBeanFactoryPostProcessors
,就是調(diào)用postProcessBeanFactory
。
5.1. getBeanFactoryPostProcessors()
??獲取的手動(dòng)注冊的BeanFactoryPostProcessor
;
??是通過beanFactory.addBeanPostProcessor()
方法設(shè)置的BeanFactoryPostProcessor
。默認(rèn)空的,因?yàn)闆]有通過addBeanFactoryPostProcessor
方法添加BeanFactoryPostProcessor
5.2 PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors()
未完待續(xù)...
6. registerBeanPostProcessors(beanFactory);
注冊BeanPostProcessor
String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);
注冊BeanPostProcessor
和invokeBeanFactoryPostProcessors
很像,并且沒什么復(fù)雜邏輯。就是將已經(jīng)注冊到beanFacory
的Bean篩選出BeanPostProcessor
然后添加到ApplicationContext
的beanPostProcessor
集合中。
主要邏輯:
:首先在容器中注冊一個(gè)
BeanPostProcessorChecker
,這個(gè)只是用來對在bean不適合所有的BeanPostProcessor
調(diào)用的情況下,打印一些日志信息。:先注冊實(shí)現(xiàn)了
PriorityOrdered
接口的BeanPostProcessor
,再注冊實(shí)現(xiàn)了Ordered
接口的的BeanPostProcessor
,然后注冊什么接口都沒實(shí)現(xiàn)的BeanPostProcessor
,最后注冊實(shí)現(xiàn)了MergedBeanDefinitionPostProcessor
接口的BeanPostProcessor
。:注冊
ApplicationListenerDetector
。用來檢測bean是否是ApplicationListener
,如果是判斷是否是單例,如果不是單例,那么刪除singtonNames
中對應(yīng)的key
。
7. initMessageSource();初始化消息源
為本context初始化消息源;
判斷beanFactory
中是否有名字為messageSource
的bean,如果有,從beanFactory
中獲取并且判斷獲取的是不是HierarchicalMessageSource
類型的,如果是設(shè)置其父級消息源;如果沒有,新建DelegatingMessageSource
類作為messageSource
的Bean。
8. initApplicationEventMulticaster();初始化應(yīng)用事件廣播器
初始化ApplicationEventMulticaster
,
首先判斷beanFactory
容器中是否存在這個(gè)廣播器:applicationEventMulticaster
;
如果存在,則用beanFactory
中的bean;如果不存在則使用新建SimpleApplicationEventMulticaster
9. onRefresh();
10. registerListeners();注冊監(jiān)聽器
在發(fā)布事件的時(shí)候會(huì)從這里注冊的監(jiān)聽器中去獲取;
11.finishBeanFactoryInitialization(beanFactory);
完成此上下文的 bean 工廠的初始化,初始化所有剩余的單例 bean。實(shí)例化所有的非懶加載單例。是ApplicationContext
刷新的時(shí)候,最重要的方法了,因?yàn)樗械腷ean,如果不是lazy-init
的都會(huì)在這一步進(jìn)行實(shí)例化,并且做一些處理。
12.finishRefresh();
完成對context的刷新
13.總結(jié)
1.prepareRefresh();對刷新進(jìn)行準(zhǔn)備,包括設(shè)置開始時(shí)間,設(shè)置激活狀態(tài),初始化Context中的占位符,子類根據(jù)其需求執(zhí)行具體準(zhǔn)備工作,而后再由父類驗(yàn)證必要參數(shù)
2.obtianFreshBeanFactory();,刷新并獲取內(nèi)部的BeanFactory對象
3.prepareBeanFactory(beanFactory);,對BeanFactory進(jìn)行準(zhǔn)備工作,包括設(shè)置類加載器和后置處理器,配置不能自動(dòng)裝配的類型,注冊默認(rèn)的環(huán)境Bean
4.postProcessBeanFactory(beanFactory);為Context的子類提供后置處理BeanFactory的擴(kuò)展能力,如想在bean定義加載完成后,開始初始化上下文之前進(jìn)行邏輯操作,可重寫這個(gè)方法
5.invokeBeanFactoryPostProcessors(beanFactory);,執(zhí)行Context中注冊的BeanFactory后置處理器,有兩張?zhí)幚砥?一種是可以注冊Bean的后置處理器,一種的針對BeanFactory的后置處理器,執(zhí)行順序是先按優(yōu)先級執(zhí)行注冊Bean的后置處理器,而后再按優(yōu)先級執(zhí)行針對BeanFactory的后置處理器
SpringBoot中會(huì)進(jìn)行注解Bean的解析,由ConfigurationClassPostProcessor觸發(fā),由ClassPathDefinitionScanner解析,并注冊到BeanFactory
6.registerBeanFactoryProcessor(beanFactory();,按優(yōu)先級順序在BeanFactory中注冊Bean的后置處理器,Bean處理器可在Bean的初始化前后處理
7.initMessageSource();初始化消息源,消息源用于支持消息的國際化
8.initApplicationEventMuticaster();初始化應(yīng)用事件廣播器,用于向ApplicationListener通知各種應(yīng)用產(chǎn)生的事件,標(biāo)準(zhǔn)的觀察者模型
9.onRefresh();,用于子類的擴(kuò)展步驟,用于特定的Context子類初始化其他的Bean
10.registerListeners();,把實(shí)現(xiàn)了ApplicationListener的類注冊到廣播器,并對廣播其中早期沒有廣播的事件進(jìn)行通知
11.finishBeanFactoryInitialization(beanFactory);,凍結(jié)所有Bean描述信息的修改,實(shí)例化非延遲加載的單例Bean
12.finishRefresh();,完成上下文的刷新工作,調(diào)用LifecycleProcessor.onRefresh(),以及發(fā)布