基于SpringBoot 2.1.5
SpringBoot
在Spring Framework
的基礎(chǔ)上增加的自動(dòng)配置(約定優(yōu)于配置)特性能夠讓開(kāi)發(fā)人員更少的關(guān)注底層而帶來(lái)更快的開(kāi)發(fā)速度。但是由此帶來(lái)的弊端是開(kāi)發(fā)人員過(guò)于依賴完善的框架功能而沒(méi)有去深入細(xì)節(jié)蜕青,只知其然而不知其所以然市咆。由此記錄一下最近在讀的SpringBoot
的源碼并記錄一下SpringBoot
的啟動(dòng)流程
SpringBoot
的啟動(dòng)邏輯在SpringApplication
這個(gè)類中蒙兰,通過(guò)構(gòu)造一個(gè)SpringApplication
并調(diào)用run
方法啟動(dòng)SpringBoot
應(yīng)用程序搜变。SpringBoot
啟動(dòng)后的主要流程:
設(shè)置webApplicationType(web應(yīng)用類型)
webApplicationType是啟動(dòng)流程中一個(gè)比較重要的屬性挠他,SpringBoot根據(jù)它的類型來(lái)創(chuàng)建Environment對(duì)象和應(yīng)用上下文對(duì)象(ApplicationContext)準(zhǔn)備應(yīng)用上下文環(huán)境(Environment)
根據(jù)上一步推斷的webApplicationType創(chuàng)建不同類型的Environment殖侵,并且將用戶的profile文件讀取到Environment中讀取profile
創(chuàng)建并配置應(yīng)用上下文對(duì)象(ApplicationContext)
根據(jù)webApplicationType創(chuàng)建不同實(shí)現(xiàn)的ApplicationContext刷新應(yīng)用上下文對(duì)象(refresh)
AbstractApplicationContext
抽象類定義了上下文對(duì)象初始化核心流程,SpringBoot
以BeanFactoryPostProcessor
的方式實(shí)現(xiàn)包掃描楞陷、自動(dòng)配置固蛾,將Bean預(yù)先加載成BeanDefinition
后并實(shí)例化后續(xù)處理
發(fā)布應(yīng)用已啟動(dòng)事件并且調(diào)用容器中的Runner
一艾凯、設(shè)置應(yīng)用類型
當(dāng)前的web應(yīng)用類型
(webApplicationType
)是在SpringApplication
的構(gòu)造函數(shù)
中設(shè)置的趾诗,設(shè)置的邏輯在WebApplicationType.deduceFromClasspath
中:
if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null)
&& !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null)
&& !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {
return WebApplicationType.REACTIVE;
}
for (String className : SERVLET_INDICATOR_CLASSES) {
if (!ClassUtils.isPresent(className, null)) {
return WebApplicationType.NONE;
}
}
return WebApplicationType.SERVLET;
可以看出SpringBoot將應(yīng)用程序分為三種類型:
Reactive
Spring
團(tuán)隊(duì)推出的Reactor
編程模型的非阻塞異步Web編程框架WebFluxServlet
基于J2EE Servlet API
的編程模型沧竟,運(yùn)行在Servlet
容器上None
非Web應(yīng)用程序
通過(guò)類路徑中是否存在WebFlux
中的Dispatcherhandler
,SpringMVC
中的DispatcherServlet
闪水、Servlet
球榆、ConfigurableWebApplicationContext
來(lái)推斷Web應(yīng)用程序類型
二持钉、準(zhǔn)備應(yīng)用上下文環(huán)境(Environment)
Environment
是SpringFramework
中一個(gè)很重要的接口篱昔,用于存放應(yīng)用程序的配置信息
PropertySource
(org.springframework.core.env.PropertySource
)是用來(lái)將一個(gè)對(duì)象以鍵值對(duì)的形式表示州刽,Spring
將多種來(lái)源的屬性鍵值對(duì)轉(zhuǎn)換成PropertySource
來(lái)表示
//SpringApplication的prepareEnvironment方法
private ConfigurableEnvironment prepareEnvironment(
SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments) {
// Create and configure the environment
ConfigurableEnvironment environment = getOrCreateEnvironment();//創(chuàng)建環(huán)境對(duì)象
configureEnvironment(environment, applicationArguments.getSourceArgs());//配置環(huán)境對(duì)象;主要是根據(jù)命令行參數(shù)配置profile
listeners.environmentPrepared(environment);//發(fā)布應(yīng)用環(huán)境已準(zhǔn)備事件
bindToSpringApplication(environment);//綁定spring.main屬性到SpringApplication對(duì)象中
if (!this.isCustomEnvironment) {
environment = new EnvironmentConverter(getClassLoader())
.convertEnvironmentIfNecessary(environment, deduceEnvironmentClass());//如果用戶設(shè)置的spring.main.web-application-type和spring推斷的類型不一致辨绊,則使用用戶設(shè)置的類型门坷,創(chuàng)建對(duì)應(yīng)的環(huán)境對(duì)象
}
ConfigurationPropertySources.attach(environment);//添加一個(gè)名為configurationProperties的PropertySource
return environment;
}
在這一步,SpringApplication
做了:
創(chuàng)建
Environment
對(duì)象
在getOrCreateEnvironment
方法中框冀,會(huì)根據(jù)之前推斷的webApplicationType
(web程序類型)創(chuàng)建不同了實(shí)現(xiàn)的Environment
對(duì)象-
配置
Environment
對(duì)象- 應(yīng)用程序如果有命令行參數(shù)明也,則在
Environment
中添加一個(gè)與這個(gè)命令行參數(shù)相關(guān)的PropertySource
- 根據(jù)命令行參數(shù)中
spring.profiles.active
屬性配置Environment
對(duì)象中的activeProfile
- 應(yīng)用程序如果有命令行參數(shù)明也,則在
-
發(fā)布
ApplicationEnvironmentPreparedEvent
(應(yīng)用環(huán)境已準(zhǔn)備)事件SpringApplication
發(fā)布完這個(gè)事件后温数,一個(gè)類型為ConfigFileApplicationListener
的監(jiān)聽(tīng)器會(huì)監(jiān)聽(tīng)這個(gè)事件撑刺,它會(huì)去讀取用戶設(shè)置的profile
文件(讀取profile
的詳細(xì)流程在下一步中) -
將
Environment
中的spring.main
屬性綁定到SpringAppilcation
對(duì)象中在執(zhí)行到這一步時(shí)够傍,
Environment
中已經(jīng)包含了用戶設(shè)置的profile
文件屬性 轉(zhuǎn)換
Environment
對(duì)象的類型
在上一步中冕屯,如果用戶使用spring.main.web-application-type
屬性手動(dòng)設(shè)置了應(yīng)用程序的webApplicationType
并且用戶設(shè)置的類型與SpringApplication
推斷出來(lái)的不一致安聘,則SpringApplication
會(huì)將環(huán)境對(duì)象轉(zhuǎn)換成用戶設(shè)置的webApplicationType
相關(guān)的類型
三浴韭、讀取profile
在創(chuàng)建
Environment
對(duì)象前念颈,SpringAppilcation
已經(jīng)將當(dāng)前類路徑j(luò)ar包下所有spring.factories
文件中的ApplicationListener
加載并實(shí)例化完畢榴芳。
ApplicationListener
:Spring Framework
中的監(jiān)聽(tīng)器接口翠语,用來(lái)監(jiān)聽(tīng)?wèi)?yīng)用程序發(fā)布的事件
監(jiān)聽(tīng)器列表中有一個(gè)類型為ConfigFileApplicationListener
的監(jiān)聽(tīng)器肌括,當(dāng)監(jiān)聽(tīng)到ApplicationEnvironmentPreparedEvent
事件時(shí)谍夭,它會(huì)從所有spring.factories
中加載EnvironmentPostProcessor
(環(huán)境后處理器)并執(zhí)行他們的postProcessEnvironment
方法(這個(gè)監(jiān)聽(tīng)器本身也是一個(gè)環(huán)境后處理器紧索,所以它也會(huì)執(zhí)行自身的postProcessEnvironment
方法珠漂,在這個(gè)方法中加載了用戶設(shè)置的profile
并以PropertySource
的形式添加到Environment
中)。
ConfigFileApplicationListener
最終會(huì)構(gòu)造一個(gè)Loader
的內(nèi)部類并調(diào)用Loader.load()
方法加載profile
荞彼;在Loader
的構(gòu)造函數(shù)中鸣皂,會(huì)去加載所有spring.factories
中的PropertySourceLoader
寞缝,SpringBoot
提供了兩個(gè)PropertySourceLoader
:
-
PropertiesPropertySourceLoader
(用來(lái)加載properties荆陆、xml文件) -
YamlPropertySourceLoader
(用來(lái)加載yml慎宾、yaml文件)
Loader.load()
加載profile
的偽代碼:
配置文件目錄
如果用戶設(shè)置了spring.config.location
屬性(用","分隔開(kāi)表示多個(gè)),則使用這個(gè)屬性值作為配置文件目錄;否則使用默認(rèn)的目錄(classpath:/,classpath:/config/,file:./,file:./config/
)和spring.config.additional-location
設(shè)置的并集作為配置文件目錄配置文件名稱
如果用戶設(shè)置了spring.config.name
屬性(用","分隔表示多個(gè))术健,則使用這個(gè)屬性作為配置文件名稱荞估;否則使用application
作為配置文件名文件擴(kuò)展名
//此時(shí)還沒(méi)有加載profile,因此兩個(gè)屬性的值只能通過(guò)命令行參數(shù)讀取到
let profiels = spring.profiles.active和spring.profiles.include設(shè)置的值
for(profile : profiles){//profiles是一個(gè)雙向隊(duì)列
for(目錄 : 配置文件目錄集合){
let 配置文件名集合 = 集合;
for(文件名 : 配置文件名集合){
for(loader : propertySourceLoader){
for(文件擴(kuò)展名 : loader.文件擴(kuò)展名){
load(profile,目錄 + 文件名 + "-" + profile + "." + 文件擴(kuò)展名);
}
}
}
}
}
在load(加載)時(shí)勘伺,如果從當(dāng)前的`profile`中讀取到了`spring.profiles.active`和`spring.profiles.include`屬性飞醉,會(huì)把解析出來(lái)的profile放入profiles中
通過(guò)以目錄 + 文件名 + "-" + profileName + "." + 文件擴(kuò)展名
的組合方式加載profile
缅帘,并將profile
以PropertySource
的形式添加到Environment
中。
profile
屬性的優(yōu)先級(jí)問(wèn)題:如果在多個(gè)profile
中設(shè)置了同一個(gè)名稱的屬性逗栽,profile屬性生效的規(guī)則是怎樣的彼宠?
同名的
profile
:根據(jù)文件后綴優(yōu)先級(jí) properties > xml > yml > yaml被引用的
profile
:例一個(gè)profile
中同時(shí)有spring.profiles.active
和spring.profiles.include
屬性,則active
的優(yōu)先級(jí) >include
的優(yōu)先級(jí)默認(rèn)的
profile
優(yōu)先級(jí)別最低-
如果把默認(rèn)的
profile
當(dāng)做第一級(jí)profile
想罕,在第一級(jí)profile
中引用的profile
(使用spring.profiles.active
或者spring.profiles.include
引用)當(dāng)做下一級(jí)的profile
按价,則下一級(jí)的profile
(可能多個(gè))優(yōu)先級(jí)高于前一級(jí)的profile
(一個(gè))楼镐,多個(gè)profile
整體的優(yōu)先級(jí)為第一級(jí)的profile
優(yōu)先級(jí)框产;例:
application.yml
內(nèi)容:
spring.profiles.active=p1,p2
spring.profiles.include=p3,p4
application-p1.yml
內(nèi)容:
spring.profiles.include=p5
則p2 > p1 > p4 > p3 > default
其中p5 > p1
秉宿,結(jié)果是p2 > p5 > p1 > p4 > p3 > default
四描睦、創(chuàng)建并配置應(yīng)用上下文對(duì)象
ApplicationContext
是Spring Framework
中最核心的接口忱叭,用來(lái)表示一個(gè)應(yīng)用的上下文韵丑;功能包括事件發(fā)布撵彻、國(guó)際化等千康,同時(shí)它也是一個(gè)BeanFactory
SpringApplication
通過(guò)webApplicationType
的類型來(lái)創(chuàng)建不同的ApplicationContext
值桩,以SERVLET
類型的webApplicationType
為例奔坟,SpringApplication
會(huì)創(chuàng)建類型為AnnotationConfigServletWebServerApplicationContext
的上下文對(duì)象咳秉;
SpringApplication
在prepareContext
方法中對(duì)上下文對(duì)象進(jìn)行預(yù)配置澜建,主要做了
-
執(zhí)行所有
ApplicationContextInitializer
的initialize
方法
這些ApplicationContextInitializer
是在SpringApplication
中的構(gòu)造函數(shù)
中加載的(通過(guò)讀取spring.factories
加載) - 發(fā)布
ApplicationContextInitializedEvent
(上下文已初始化)事件 - 發(fā)布
ApplicationPreparedEvent
(上下文已準(zhǔn)備)事件
五炕舵、刷新應(yīng)用上下文對(duì)象
這里是
ApplicationContext
真正開(kāi)始初始化容器和創(chuàng)建bean
的階段,其中bean
的整個(gè)生命周期可以從這一步驟看出來(lái)徊件;Spring Framework
中的所有ApplicationContext
實(shí)現(xiàn)都直接或間接繼承自AbstracttApplicationContext
睹耐,它的refresh
方法描述了整個(gè)上下文的初始化邏輯
以AnnotationConfigServletWebServerApplicationContext
(當(dāng)應(yīng)用的webApplicationType為Servlet時(shí)使用)這個(gè)實(shí)現(xiàn)類為例
AbstractApplicationContext的refresh方法
synchronized (this.startupShutdownMonitor) {
prepareRefresh();//(1)
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();//(2)
prepareBeanFactory(beanFactory);//(3)
try {
postProcessBeanFactory(beanFactory);//(4)
invokeBeanFactoryPostProcessors(beanFactory);//(5)
registerBeanPostProcessors(beanFactory);//(6)
initMessageSource();//(7)
initApplicationEventMulticaster();//(8)
onRefresh();//(9)
registerListeners();//(10)
finishBeanFactoryInitialization(beanFactory);//(11)
finishRefresh();//(12)
}catch (BeansException ex) {
//疏橄。。表牢。崔兴。敲茄。堰燎。
}
finally {
resetCommonCaches();
}
}
1. 準(zhǔn)備更新上下文時(shí)的預(yù)備工作:
- 初始化
PropertySource
- 驗(yàn)證
Enrivonment
中必要的屬性
2. 獲取上下文的內(nèi)部BeanFactory
內(nèi)部BeanFactory
的實(shí)現(xiàn)類是DefaultListableBeanFactory
3. 對(duì)BeanFactory做些預(yù)備工作:
- 設(shè)置
BeanFactory
的Bean
類加載器赊淑、Bean
表達(dá)式解析器陶缺、屬性編輯器注冊(cè)表 - 添加類型為
ApplicationContextAwareProcessor
饱岸、ApplicationListenerDetector
的BeanPostProcessor
- 讓
BeanFactory
在自動(dòng)裝配時(shí)忽略一些接口類型 - 注冊(cè)可解析的依賴(自動(dòng)裝配時(shí)碰到這些類型直接注入,包括
BeanFactory
苫费、ResourceLoader
、ApplicationEventPublisher
荠诬、ApplicationContext
) - 在
BeanFactory
中注冊(cè)一些單例對(duì)象柑贞,包括environment
钧嘶、systemProperties
有决、systemEnvironment
4. 對(duì)BeanFactory進(jìn)行預(yù)處理
- 添加一個(gè)
WebApplicationContextServletContextAwareProcessor
的BeanPostProcessor
- 使
BeanFactory
自動(dòng)裝配時(shí)忽略ServletContextAware
接口 - 在
BeanFactory
中注冊(cè)request
新荤、session
兩種scope - 注冊(cè)可解析的依賴(自動(dòng)裝配時(shí)碰到這些類型可以注解注入,包括
ServletRequest
苛骨、ServletResponse
、HttpSession
俐筋、WebRequest
)
5. 執(zhí)行容器中的BeanFactoryPostProcessor執(zhí)行到這時(shí)容器已經(jīng)注冊(cè)了三個(gè)BeanFactoryPostProcessor澄者,分別為
-
SharedMetadataReaderFactoryContextInitializer$CachingMetadataReaderFactoryPostProcessor
ApplicationContexttInitializer
初始化時(shí)注冊(cè) -
ConfigurationWarningsApplicationContextInitializer#ConfigurationWarningsPostProcessor
ApplicationContexttInitializer
初始化時(shí)注冊(cè) -
ConfigFileApplicationListener$PropertySourceOrderingPostProcessor
ApplicationPreparedEvent
事件發(fā)布時(shí)由ConfigFileApplicationListener
注冊(cè)
BeanDefinitionRegistryPostProcessor
是一種特殊的BeanFactoryPostProcessor
,可以對(duì)BeanDefinition
的注冊(cè)表進(jìn)行預(yù)處理
在
BeanFactory
中找到已注冊(cè)的BeanFactoryPostProcessor
抱怔,執(zhí)行其中類型為BeanDefinitionRegistryPostProcessor
的postProcessBeanDefinitionRegistry
方法-
循環(huán)從BeanFactory中獲取
BeanDefinitionRegistryPostProcessor
(從BeanDefinition注冊(cè)表中獲取屈留,和上一步的來(lái)源不一樣)灌危;有一個(gè)ConfigurationClassPostProcessor
(ApplicationContext
的構(gòu)造函數(shù)中注冊(cè)的)
ConfigurationClassPostProcessor會(huì)執(zhí)行SpringBoot的自動(dòng)裝配功能勇蝙,將spring.factories中類型為EnableAutoConfiguration的類讀取成BeanDefinition并過(guò)濾掉不滿足條件的然后注冊(cè)到BeanFactory中味混。詳細(xì)步驟在下一章這一步驟會(huì)不斷從BeanFactory中獲取沒(méi)有執(zhí)行的BeanDefinitionRegistryPostProcessor并執(zhí)行(可能用戶會(huì)里面注冊(cè)同類型的處理器)直到?jīng)]有找到新的BeanDefinitionRegistryPostProcessor
包掃描翁锡、自動(dòng)裝配的功能都在ConfigurationClassPostProcessor中完成,執(zhí)行完這一步后角溃,所有Bean都會(huì)加載成BeanDefinition放入容器中
執(zhí)行他們的
postProcessBeanFactory
方法對(duì)BeanFactory
進(jìn)行后處理
6. 注冊(cè)BeanPostProcessor
BeanPostProcessor:
Bean生命周期的鉤子开镣,允許用戶對(duì)實(shí)例化后的Bean進(jìn)行操作
從BeanFactory中獲取所有
BeanPostProcessor
在
BeanFactory
中注冊(cè)一個(gè)類型為BeanPostProcessorChecker的BeanPostProcessor
將所有
BeanPostProcessor
按照實(shí)現(xiàn)了PriorityOrdered
邪财、Ordered
树埠、沒(méi)有實(shí)現(xiàn)排序接口
的順序注冊(cè)所有BeanPostProcessor
到BeanFactory
在
BeanFactory
中注冊(cè)一個(gè)類型為ApplicationListenerDetector
的BeanPostProcessor
7. 初始化MessageSource(國(guó)際化相關(guān))//忽略
8. 初始化容器事件廣播器(用來(lái)發(fā)布事件)
- 構(gòu)造了一個(gè)SimpleApplicationEventMulticaster當(dāng)成默認(rèn)的事件廣播器
9. 初始化一些特殊的Bean,主要做了:
- 初始化ThemeSource(跟國(guó)際化相關(guān)的接口)
- 創(chuàng)建WebServer
10. 將所有監(jiān)聽(tīng)器注冊(cè)到前兩步創(chuàng)建的事件廣播器中
11. 結(jié)束B(niǎo)eanFactory的初始化工作(這一步主要用來(lái)將所有的單例BeanDefinition實(shí)例化)
從
BeanFactory
中獲取所有的BeanDefinition
的beanName
并遍歷對(duì)
Bean
執(zhí)行所有已注冊(cè)的InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation
方法(如果這個(gè)方法返回了一個(gè)Bean,Spring不會(huì)對(duì)這個(gè)Bean的屬性進(jìn)行注入,并且這個(gè)Bean的生命周期也會(huì)缺少幾個(gè)步驟)
PS:只要其中有一個(gè)方法的返回值不為null,則會(huì)立即返回這個(gè)Bean绊袋,這個(gè)Bean的生命周期和正常的Bean不同(Spring對(duì)這個(gè)類型的BeanPostProcessor的注釋是讓它有機(jī)會(huì)能返回一個(gè)代理對(duì)象)實(shí)例化bean
對(duì)
Bean
執(zhí)行所有MergedBeanDefinitionPostProcessor.prostProcessMergedBeanDefinition
(用來(lái)修改BeanDefinition的信息)-
對(duì)Bean屬性進(jìn)行填充(還有利用BeanPostProcessor對(duì)特殊Bean創(chuàng)建代理等暫時(shí)不討論)
- 獲取
BeanFactory
中所有InstantiationAwareBeanPostProcessor
,對(duì)Bean
執(zhí)行postProcessAfterInstantiation
方法(通常展姐,這個(gè)方法應(yīng)該返回true圾笨,如果返回false擂达,后續(xù)的postProcessAfterInstantiation
方法就不會(huì)執(zhí)行了) - 同上板鬓,獲取所有
InstantiationAwareBeanPostProcessor
穗熬,對(duì)每一個(gè)InstantiationAwareBeanPostProcessor
分兩次調(diào)用
1.postProcessProperties
,如果返回null,則繼續(xù)調(diào)用下一步-
postProcessPropertyValues
(返回的PropertyValues
是最終使用的PropertyValues
唤蔗。如果這一步返回null,則不會(huì)執(zhí)行后面的InstantiationAwareBeanPostProcessor
) - 如果上一步返回的
PropertyValues
有屬性妓柜,則將屬性應(yīng)用到bean
上
-
- 獲取
對(duì)實(shí)現(xiàn)了
BeanNameAware
棍掐、BeanClassLoaderAware
作煌、BeanFactoryAware
的接口進(jìn)行接口調(diào)用對(duì)
Bean
執(zhí)行BeanPostProcessor.postProcessBeforeInitialization
方法對(duì)實(shí)現(xiàn)了
InitializingBean
的Bean
調(diào)用接口方法,然后調(diào)用init-method(可以是@PostConstruct標(biāo)注的方法)對(duì)
Bean
執(zhí)行PostProcessor.postProcessAfterInitialization
方法如果
Bean
是一個(gè)SmartInitializingSingleton
,則調(diào)用Bean
的afterSingletonsInstantiated
方法
- 對(duì)于
EnvironmentAware
奏寨、ResourceLoaderAware
病瞳、ApplicationEventPublisherAware
套菜、MessageSourceAware
、AppilcationContextAware
等接口嚎于,是使用ApplicationContextAwareProcessor
這個(gè)BeanPostProcessor
(postProcessBeforeInitialization
方法)實(shí)現(xiàn)調(diào)用的- 步驟2中于购,如果
postProcessBeforeInstantiation
返回了一個(gè)bean肋僧,則立馬會(huì)對(duì)bean執(zhí)行步驟8的PosttProcessor.postProcessAfterInitialization方法
12.afterRefresh(上下文刷新完畢)
- 初始
LifecycleProcessor
(生命周期處理器),向BeanFactory
注冊(cè)一個(gè)DefaultLifecycleProcessor
- 調(diào)用
LifecycleProcessor
的onrefresh
方法(找到所有已注冊(cè)的SmartLifecycle
,根據(jù)isRunning
和isAutoStartup
的條件判斷辫诅,執(zhí)行SmartLifecycle
的start
方法) - 在
ServletWebServerApplicationContetxt
中炕矮,啟動(dòng)了WebServer
并發(fā)布了ServletWebServerInitializedEvent
事件
總結(jié):
Spring容器中單例對(duì)象的生命周期
使用BeanFactoryPostProcessor對(duì)BeanFactory進(jìn)行預(yù)處理
對(duì)未實(shí)例化的
Bean
調(diào)用InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation
方法實(shí)例化Bean(此時(shí)會(huì)調(diào)用Bean構(gòu)造函數(shù))
對(duì)
Bean
調(diào)用MergedBeanDefinitionPostProcessor.prostProcessMergedBeanDefinition
可用來(lái)修改BeanDefinition信息對(duì)
Bean
調(diào)用InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation
方法對(duì)
Bean
調(diào)用InstantiationAwareBeanPostProcessor.postProcessProperties
可用來(lái)修改Bean的屬性配置對(duì)
Bean
調(diào)用InstantiationAwareBeanPostProcessor.postProcessPropertyValues
可用來(lái)修改Bean的屬性配置對(duì)實(shí)現(xiàn)了
BeanNameAware肤视、BeanClassLoaderAware、BeanFactoryAware
的Bean
進(jìn)行接口調(diào)用注入屬性對(duì)
Bean
調(diào)用BeanPostProcessor.postProcessBeforeInitialization
可對(duì)實(shí)例化的Bean
進(jìn)行操作對(duì)實(shí)現(xiàn)了
InitializingBean
的Bean
調(diào)用接口方法,然后有初始化方法(可以是@PostConstruct標(biāo)注的方法)的話調(diào)用初始化方法對(duì)
Bean
執(zhí)行PostProcessor.postProcessAfterInitialization
方法可對(duì)實(shí)例化的Bean
進(jìn)行操作如果
Bean
實(shí)現(xiàn)了SmartInitializingSingleton
接口,則調(diào)用Bean的afterSingletonsInstantiated
方法
SpringApplication
在refresh
方法調(diào)用結(jié)束后困后,在JVM上注冊(cè)了一個(gè)shutdownHook
锯仪,JVM正常關(guān)閉時(shí)會(huì)調(diào)用,其中做了一些資源清理和調(diào)用Bean
的close
的方法工作(單例Bean生命周期的一部分)
六救鲤、后續(xù)處理
- 發(fā)布應(yīng)用程序已啟動(dòng)(
ApplicationStartedEvent
)事件 - 在
BeanFactory
中獲取所有ApplicationRunner
和CommandLineRunner
并調(diào)用他們的run
方法