Spring Boot啟動過程及回調接口匯總
鏈接: https://www.itcodemonkey.com/article/1431.html
注:本文基於spring-boot 1.4.1.RELEASE, spring 4.3.3.RELEASE撰寫。
啟動順序
Spring boot的啟動代碼一般是這樣的:
1
2
3
4
5
6
|
@SpringBootApplication
public
class
SampleApplication {
public
static
void
main(String[] args)
throws
Exception {
SpringApplication.run(SampleApplication.
class
, args);
}
}
|
初始化SpringApplication
1、SpringApplication#run(Object source, String... args)
#L1174
2、SpringApplication#L1186 -> SpringApplication(sources)
#L236
3、SpringApplication#initialize(Object[] sources)
#L256 javadoc
4、SpringApplication#L257 添加source(復數),SpringApplication
使用source來構建Bean。一般來說在run
的時候都會把@SpringBootApplication標記的類(本例中是SampleApplication)放到sources
參數里,然后由這個類出發找到Bean的定義。
5、SpringApplication#L261 初始化ApplicationContextInitializer列表(見附錄)
6、SpringApplication#L263 初始化ApplicationListener列表(見附錄)
7、SpringApplication#L1186 -> SpringApplication#run(args)
#L297,進入運行階段
推送ApplicationStartedEvent
SpringApplication#run(args)
#L297
1、SpringApplication#L303 初始化SpringApplicationRunListeners (SpringApplicationRunListener的集合)。它內部只包含EventPublishingRunListener。
2、SpringApplication#L304 推送ApplicationStartedEvent給所有的ApplicationListener(見附錄)。 下面是關心此事件的listener:
准備Environment
SpringApplication#run(args)
#L297->#L308->prepareEnvironment(...)
#L331准備ConfigurableEnvironment。
1、SpringApplication#L335 創建StandardEnvironment(見附錄)。
2、SpringApplication#L336 配置StandardEnvironment,將命令行和默認參數整吧整吧,添加到MutablePropertySources。
3、SpringApplication#L337 推送ApplicationEnvironmentPreparedEvent給所有的ApplicationListener(見附錄)。下面是關心此事件的listener:
5、FileEncodingApplicationListener
6、AnsiOutputApplicationListener
7、ConfigFileApplicationListener(見附錄)
8、DelegatingApplicationListener
9、ClasspathLoggingApplicationListener
可以參考官方文檔了解StandardEnvironment構建好之后,其MutablePropertySources內部到底有些啥東東。
創建及准備ApplicationContext
SpringApplication#run(args)
#L297
1、SpringApplication#L311->SpringApplication#createApplicationContext()
#L583創建ApplicationContext。可以看到實際上創建的是AnnotationConfigApplicationContext或AnnotationConfigEmbeddedWebApplicationContext。
2、在構造AnnotationConfigApplicationContext的時候,間接注冊了一個BeanDefinitionRegistryPostProcessor的Bean:ConfigurationClassPostProcessor。經由AnnotatedBeanDefinitionReader構造函數->AnnotationConfigUtils.registerAnnotationConfigProcessors。
3、SpringApplication#L313->SpringApplication#prepareContext(...)
#L344准備ApplicationContext
4、SpringApplication#L347->context.setEnvironment(environment)
,把之前准備好的Environment塞給ApplicationContext
5、SpringApplication#L348->postProcessApplicationContext(context)
#L605,給ApplicationContext設置了一些其他東西
6、SpringApplication#L349->applyInitializers(context)
#L630,調用之前准備好的ApplicationContextInitializer
7、SpringApplication#L350->listeners.contextPrepared(context)
->EventPublishingRunListener.contextPrepared,但實際上啥都沒做。
8、SpringApplication#L366->load
#L687,負責將source(復數)里所定義的Bean加載到ApplicationContext里,在本例中就是SampleApplication,這些source是在初始化SpringApplication階段獲得的。
9、SpringApplication#L367->listeners.contextLoaded(context)
->EventPublishingRunListener.contextLoaded。
10、將SpringApplication自己擁有的ApplicationListener加入到ApplicationContext
11、發送ApplicationPreparedEvent。目前已知關心這個事件的有ConfigFileApplicationListener、LoggingApplicationListener、ApplicationPidFileWriter
要注意的是在這個階段,ApplicationContext里只有SampleApplication,SampleApplication是Bean的加載工作的起點。
刷新ApplicationContext
根據前面所講,這里的ApplicationContext實際上是GenericApplicationContext ->AnnotationConfigApplicationContext或者AnnotationConfigEmbeddedWebApplicationContext
SpringApplication#run(args)
#L297 ->#L315->SpringApplication#refreshContext(context)
#L370 ->#L371->SpringApplication#refresh(context)
#L759 ->#L761->AbstractApplicationContext#refresh
AbstractApplicationContext#L507
1、AbstractApplicationContext#L510->AbstractApplicationContext#prepareRefresh()
#L575,做了一些初始化工作,比如設置了當前Context的狀態,初始化propertySource(其實啥都沒干),檢查required的property是否都已在Environment中(其實並沒有required的property可供檢查)等。
2、AbstractApplicationContext#L513->obtainFreshBeanFactory()
#L611,獲得BeanFactory,實際上這里獲得的是DefaultListableBeanFactory
3、AbstractApplicationContext#L516->prepareBeanFactory(beanFactory)
#L625准備BeanFactory
4、給beanFactory設置了ClassLoader
5、給beanFactory設置了SpEL解析器
6、給beanFactory設置了PropertyEditorRegistrar
7、給beanFactory添加了ApplicationContextAwareProcessor(BeanPostProcessor的實現類),需要注意的是它是第一個被添加到BeanFactory的BeanPostProcessor
8、給beanFactory設置忽略解析以下類的依賴:ResourceLoaderAware、ApplicationEventPublisherAware、MessageSourceAware、ApplicationContextAware、EnvironmentAware。原因是注入這些回調接口本身沒有什么意義。
9、給beanFactory添加了以下類的依賴解析:BeanFactory、ResourceLoader、ApplicationEventPublisher、ApplicationContext
10、給beanFactory添加LoadTimeWeaverAwareProcessor用來處理LoadTimeWeaverAware的回調,在和AspectJ集成的時候會用到
11、把getEnvironment()
作為Bean添加到beanFactory中,Bean Name: environment
12、把getEnvironment().getSystemProperties()
作為Bean添加到beanFactory中,Bean Name: systemProperties
13、把getEnvironment().getSystemEnvironment()
作為Bean添加到beanFactory中,Bean Name: systemEnvironment
14、AbstractApplicationContext#L520->postProcessBeanFactory(beanFactory)
,后置處理BeanFactory,實際啥都沒做
15、AbstractApplicationContext#L523->invokeBeanFactoryPostProcessors(beanFactory)
,利用BeanFactoryPostProcessor,對beanFactory做后置處理。調用此方法時有四個BeanFactoryPostProcessor:
16、SharedMetadataReaderFactoryContextInitializer的內部類CachingMetadataReaderFactoryPostProcessor,是在 創建及准備ApplicationContext 2.3 時添加的:#L57
17、ConfigurationWarningsApplicationContextInitializer的內部類ConfigurationWarningsPostProcessor,是在 創建及准備ApplicationContext 2.3 時添加的:#L60
18、ConfigFileApplicationListener的內部類PropertySourceOrderingPostProcessor,是在 創建及准備ApplicationContext 2.6 時添加的:#L158->#L199->#L244
19、ConfigurationClassPostProcessor,負責讀取BeanDefinition是在 創建及准備ApplicationContext 1.1 時添加的
20、AbstractApplicationContext#L526->registerBeanPostProcessors(beanFactory)
,注冊BeanPostProcessor
21、AbstractApplicationContext#L529->initMessageSource()
#L704,初始化MessageSource,不過其實此時的MessageSource是個Noop對象。
22、AbstractApplicationContext#L532->initApplicationEventMulticaster()
#L739,初始化ApplicationEventMulticaster。
23、AbstractApplicationContext#L535->onRefresh()
#L793,這個方法啥都沒做
24、AbstractApplicationContext#L538->registerListeners()
#L801,把自己的ApplicationListener注冊到ApplicationEventMulticaster里,並且將之前因為沒有ApplicationEventMulticaster而無法發出的ApplicationEvent發送出去。
25、AbstractApplicationContext#L541->finishBeanFactoryInitialization
#L828。注意#L861,在這一步的時候才會實例化所有non-lazy-init bean,這里說的實例化不只是new而已,注入、BeanPostProcessor都會執行。
26、AbstractApplicationContext#L544->finishRefresh()
#L869。
27、在#L877發送了ContextRefreshedEvent
調用 ApplicationRunner 和 CommandLineRunner
SpringApplication#run(args)
#L297 ->afterRefresh(context, applicationArguments)
#L316 ->callRunners(context, args)
#L771 ->#L774 先后調用了當前ApplicationContext中的ApplicationRunner和CommandLineRunner。關於它們的相關文檔可以看這里。
需要注意的是,此時的ApplicationContext已經刷新完畢了,該有的Bean都已經有了。
推送ApplicationReadyEvent or ApplicationFailedEvent
SpringApplication#run(args)
#L297->listeners.finished(context, null)
#L317 間接地調用了EventPublishingRunListener#getFinishedEvent
EventPublishingRunListener#L96,發送了ApplicationReadyEvent或ApplicationFailedEvent
回調接口
ApplicationContextInitializer
加載方式:讀取classpath*:META-INF/spring.factories
中key等於org.springframework.context.ApplicationContextInitializer
的property列出的類
排序方式:AnnotationAwareOrderComparator
已知清單1:spring-boot-1.4.1.RELEASE.jar!/META-INF/spring.factories
1、ConfigurationWarningsApplicationContextInitializer(優先級:0)
2、ContextIdApplicationContextInitializer(優先級:Ordered.LOWEST_PRECEDENCE – 10)
3、DelegatingApplicationContextInitializer(優先級:無=Ordered.LOWEST_PRECEDENCE)
4、ServerPortInfoApplicationContextInitializer(優先級:無=Ordered.LOWEST_PRECEDENCE)
已知清單2:spring-boot-autoconfigure-1.4.1.RELEASE.jar!/META-INF/spring.factories
1、SharedMetadataReaderFactoryContextInitializer(優先級:無=Ordered.LOWEST_PRECEDENCE)
2、AutoConfigurationReportLoggingInitializer(優先級:無=Ordered.LOWEST_PRECEDENCE)
ApplicationListener
加載方式:讀取classpath*:META-INF/spring.factories
中key等於org.springframework.context.ApplicationListener
的property列出的類
排序方式:AnnotationAwareOrderComparator
已知清單1:spring-boot-1.4.1.RELEASE.jar!/META-INF/spring.factories中定義的
1、ClearCachesApplicationListener(優先級:無=Ordered.LOWEST_PRECEDENCE)
2、ParentContextCloserApplicationListener(優先級:Ordered.LOWEST_PRECEDENCE – 10)
3、FileEncodingApplicationListener(優先級:Ordered.LOWEST_PRECEDENCE)
4、AnsiOutputApplicationListener(優先級:ConfigFileApplicationListener.DEFAULT_ORDER + 1)
5、ConfigFileApplicationListener(優先級:Ordered.HIGHEST_PRECEDENCE + 10)
6、DelegatingApplicationListener(優先級:0)
7、LiquibaseServiceLocatorApplicationListener(優先級:無=Ordered.LOWEST_PRECEDENCE)
8、ClasspathLoggingApplicationListener(優先級:LoggingApplicationListener的優先級 + 1)
9、LoggingApplicationListener(優先級:Ordered.HIGHEST_PRECEDENCE + 20)
已知清單2:spring-boot-autoconfigure-1.4.1.RELEASE.jar!/META-INF/spring.factories中定義的
SpringApplicationRunListener
加載方式:讀取classpath*:META-INF/spring.factories
中key等於org.springframework.boot.SpringApplicationRunListener
的property列出的類
排序方式:AnnotationAwareOrderComparator
已知清單:spring-boot-1.4.1.RELEASE.jar!/META-INF/spring.factories定義的
1、org.springframework.boot.context.event.EventPublishingRunListener(優先級:0)
EnvironmentPostProcessor
EnvironmentPostProcessor可以用來自定義StandardEnvironment(相關文檔)。
加載方式:讀取classpath*:META-INF/spring.factories
中key等於org.springframework.boot.env.EnvironmentPostProcessor
的property列出的類
排序方式:AnnotationAwareOrderComparator
已知清單:spring-boot-1.4.1.RELEASE.jar!/META-INF/spring.factories定義的
1、CloudFoundryVcapEnvironmentPostProcessor(優先級:ConfigFileApplicationListener.DEFAULT_ORDER – 1)
2、SpringApplicationJsonEnvironmentPostProcessor(優先級:Ordered.HIGHEST_PRECEDENCE + 5)
BeanPostProcessor
用來對Bean實例進行修改的勾子,根據Javadoc ApplicationContext會自動偵測到BeanPostProcessor Bean,然后將它們應用到后續創建的所有Bean上。
BeanFactoryPostProcessor和BeanDefinitionRegistryPostProcessor
PostProcessorRegistrationDelegate負責調用BeanDefinitionRegistryPostProcessor和BeanFactoryPostProcessor。BeanDefinitionRegistryPostProcessor在BeanFactoryPostProcessor之前被調用。
*Aware
*Aware是一類可以用來獲得Spring對象的interface,這些interface都繼承了Aware,已知的有:
@Configuration 和 Auto-configuration
@Configuration替代xml來定義BeanDefinition的一種手段。Auto-configuration也是定義BeanDefinition的一種手段。
這兩者的相同之處有:
1、都是使用@Configuration注解的類,這些類里都可以定義@Bean、@Import、@ImportResource。
都可以使用@Condition*來根據情況選擇是否加載
而不同之處有:
1、加載方式不同:
普通@Configuration則是通過掃描package path加載的
Auto-configuration的是通過讀取
classpath*:META-INF/spring.factories
中key等於org.springframework.boot.autoconfigure.EnableAutoConfiguration
的property列出的@Configuration加載的
2、加載順序不同:普通@Configuration的加載在Auto-configuration之前,但是有例外情況,看下面。
3、內部加載順序可控上的不同:
普通@Configuration則無法控制加載順序
Auto-configuration可以使用@AutoConfigureOrder、@AutoConfigureBefore、@AutoConfigureAfter
以下情況下Auto-configuration會在普通@Configuration前加載:
1、Auto-configuration如果出現在最初的掃描路徑里(@ComponentScan),就會被提前加載到,然后被當作普通的@Configuration處理,這樣@AutoConfigureBefore和@AutoConfigureAfter就沒用了。參看例子代碼里的InsideAutoConfiguration和InsideAutoConfiguration2。
2、Auto-configuration如果提供BeanPostProcessor,那么它會被提前加載。參見例子代碼里的BeanPostProcessorAutoConfiguration。
3、Auto-configuration如果使用了ImportBeanDefinitionRegistrar,那么ImportBeanDefinitionRegistrar會被提前加載。參見例子代碼里的ImportBeanDefinitionRegistrarAutoConfiguration。
4、Auto-configuration如果使用了ImportSelector,那么ImportSelector會被提前加載。參見例子代碼里的UselessDeferredImportSelectorAutoConfiguration。
參考EnableAutoConfiguration和附錄EnableAutoConfigurationImportSelector了解Spring boot內部處理機制。
AnnotatedBeanDefinitionReader
這個類用來讀取@Configuration和@Component,並將BeanDefinition注冊到ApplicationContext里。
ConfigurationClassPostProcessor
ConfigurationClassPostProcessor是一個BeanDefinitionRegistryPostProcessor,負責處理@Configuration。
需要注意一個煙霧彈:看#L296->ConfigurationClassUtils#L209。而order的值則是在ConfigurationClassUtils#L122從注解中提取的。 這段代碼似乎告訴我們它會對@Configuration進行排序,然后按次序加載。 實際上不是的,@Configuration是一個遞歸加載的過程。在本例中,是先從SampleApplication開始加載的,而事實上在這個時候,也就只有SampleApplication它自己可以提供排序。 而之后則直接使用了ConfigurationClassParser,它里面並沒有排序的邏輯。
關於排序的方式簡單來說是這樣的:@Configuration的排序根據且只根據@Order排序,如果沒有@Order則優先級最低。
ConfigurationClassParser
前面講了ConfigurationClassPostProcessor使用ConfigurationClassParser,實際上加載@Configuration的工作是在這里做的。
下面講以下加載的順序:
1、以SampleApplication為起點開始掃描
2、掃描得到所有的@Configuration和@Component,從中讀取BeanDefinition並導入:
3、如果@Configuration注解了@Import
4、如果使用的是ImportSelector,則遞歸導入
5、如果使用的是ImportBeanDefinitionRegistrar,則遞歸導入
6、如果使用的是DeferredImportSelector,則僅收集不導入
7、如果@Configuration注解了@ImportResource,則遞歸導入
8、迭代之前收集的DeferredImportSelector,遞歸導入
那Auto-configuration在哪里呢? 實際上是在第3步里,@SpringBootApplication存在注解@EnableAutoConfiguration,它使用了EnableAutoConfigurationImportSelector, EnableAutoConfigurationImportSelector是一個DeferredImportSelector,所以也就是說,Auto-configuration是在普通@Configuration之后再加載的。
順帶一提,如果Auto-configuration里再使用DeferredImportSelector,那么效果和使用ImportSelector效果是一樣的,不會再被延后處理。參見例子代碼里的UselessDeferredImportSelectorAutoConfiguration。
EnableAutoConfigurationImportSelector
EnableAutoConfigurationImportSelector負責導入Auto-configuration。
它利用AutoConfigurationSorter對Auto-configuration進行排序。邏輯算法是:
1、先根據類名排序
2、再根據@AutoConfigureOrder排序,如果沒有@AutoConfigureOrder則優先級最低
3、再根據@AutoConfigureBefore,@AutoConfigureAfter排序
內置類說明
LoggingApplicationListener
LoggingApplicationListener用來配置日志系統的,比如logback、log4j。Spring boot對於日志有詳細解釋,如果你想自定義日志配置,那么也請參考本文中對於LoggingApplicationListener的被調用時機的說明以獲得更深入的了解。
StandardEnvironment
StandardEnvironment有一個MutablePropertySources,它里面有多個PropertySource,PropertySource負責提供property(即property的提供源),目前已知的PropertySource實現有:MapPropertySource、SystemEnvironmentPropertySource、CommandLinePropertySource等。當StandardEnvironment查找property值的時候,是從MutablePropertySources里依次查找的,而且一旦查找到就不再查找,也就是說如果要覆蓋property的值,那么就得提供順序在前的PropertySource。
ConfigFileApplicationListener
ConfigFileApplicationListener用來將application.properties
加載到StandardEnvironment中。
ConfigFileApplicationListener內部使用了EnvironmentPostProcessor(見附錄)自定義StandardEnvironment
ApplicationContextAwareProcessor
ApplicationContextAwareProcessor實現了BeanPostProcessor接口,根據javadoc這個類用來調用以下接口的回調方法:
3、ApplicationEventPublisherAware
AnnotationConfigApplicationContext
根據javadoc,這個類用來將@Configuration和@Component作為輸入來注冊BeanDefinition。
特別需要注意的是,在javadoc中講到其支持@Bean的覆蓋:
In case of multiple @Configuration classes, @Bean methods defined in later classes will override those defined in earlier classes. This can be leveraged to deliberately override certain bean definitions via an extra @Configuration class.
它使用AnnotatedBeanDefinitionReader來讀取@Configuration和@Component。
AnnotatedBeanDefinitionReader
AnnotatedBeanDefinitionReader在其構造函數內部間接(AnnotationConfigUtils#L145)的給BeanFactory注冊了幾個與BeanDefinition相關注解的處理器。
1、ConfigurationClassPostProcessor
2、AutowiredAnnotationBeanPostProcessor
3、RequiredAnnotationBeanPostProcessor
4、CommonAnnotationBeanPostProcessor