Spring Boot啟動過程及回調接口匯總


Spring Boot啟動過程及回調接口匯總 
鏈接: https://www.itcodemonkey.com/article/1431.html


注:本文基於spring-boot 1.4.1.RELEASEspring 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:

4、BackgroundPreinitializer

5、FileEncodingApplicationListener

6、AnsiOutputApplicationListener

7、ConfigFileApplicationListener(見附錄)

8、DelegatingApplicationListener

9、ClasspathLoggingApplicationListener

10、LoggingApplicationListener

11、ApplicationPidFileWriter


可以參考官方文檔了解StandardEnvironment構建好之后,其MutablePropertySources內部到底有些啥東東。

創建及准備ApplicationContext

SpringApplication#run(args)#L297

1、SpringApplication#L311->SpringApplication#createApplicationContext()#L583創建ApplicationContext。可以看到實際上創建的是AnnotationConfigApplicationContextAnnotationConfigEmbeddedWebApplicationContext


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。目前已知關心這個事件的有ConfigFileApplicationListenerLoggingApplicationListenerApplicationPidFileWriter


要注意的是在這個階段,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#refreshAbstractApplicationContext#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添加了ApplicationContextAwareProcessorBeanPostProcessor的實現類),需要注意的是它是第一個被添加到BeanFactoryBeanPostProcessor


8、給beanFactory設置忽略解析以下類的依賴:ResourceLoaderAwareApplicationEventPublisherAwareMessageSourceAwareApplicationContextAwareEnvironmentAware。原因是注入這些回調接口本身沒有什么意義。


9、給beanFactory添加了以下類的依賴解析:BeanFactoryResourceLoaderApplicationEventPublisherApplicationContext


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中的ApplicationRunnerCommandLineRunner。關於它們的相關文檔可以看這里

需要注意的是,此時的ApplicationContext已經刷新完畢了,該有的Bean都已經有了。

推送ApplicationReadyEvent or ApplicationFailedEvent

SpringApplication#run(args)#L297->listeners.finished(context, null)#L317 間接地調用了EventPublishingRunListener#getFinishedEventEventPublishingRunListener#L96,發送了ApplicationReadyEventApplicationFailedEvent

回調接口

ApplicationContextInitializer

javadoc 相關文檔

加載方式:讀取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

javadoc 相關文檔

加載方式:讀取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中定義的

10、BackgroundPreinitializer


SpringApplicationRunListener

javadoc

加載方式:讀取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

javadoc 相關文檔

用來對Bean實例進行修改的勾子,根據Javadoc ApplicationContext會自動偵測到BeanPostProcessor Bean,然后將它們應用到后續創建的所有Bean上。

BeanFactoryPostProcessor和BeanDefinitionRegistryPostProcessor

相關文檔

PostProcessorRegistrationDelegate負責調用BeanDefinitionRegistryPostProcessorBeanFactoryPostProcessorBeanDefinitionRegistryPostProcessorBeanFactoryPostProcessor之前被調用。

*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、內部加載順序可控上的不同:


以下情況下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

它利用AutoConfigurationSorterAuto-configuration進行排序。邏輯算法是:

1、先根據類名排序

2、再根據@AutoConfigureOrder排序,如果沒有@AutoConfigureOrder則優先級最低

3、再根據@AutoConfigureBefore@AutoConfigureAfter排序


內置類說明

LoggingApplicationListener

LoggingApplicationListener用來配置日志系統的,比如logback、log4j。Spring boot對於日志有詳細解釋,如果你想自定義日志配置,那么也請參考本文中對於LoggingApplicationListener的被調用時機的說明以獲得更深入的了解。

StandardEnvironment

StandardEnvironment有一個MutablePropertySources,它里面有多個PropertySourcePropertySource負責提供property(即property的提供源),目前已知的PropertySource實現有:MapPropertySourceSystemEnvironmentPropertySourceCommandLinePropertySource等。當StandardEnvironment查找property值的時候,是從MutablePropertySources里依次查找的,而且一旦查找到就不再查找,也就是說如果要覆蓋property的值,那么就得提供順序在前的PropertySource

ConfigFileApplicationListener

ConfigFileApplicationListener用來將application.properties加載到StandardEnvironment中。

ConfigFileApplicationListener內部使用了EnvironmentPostProcessor(見附錄)自定義StandardEnvironment

ApplicationContextAwareProcessor

ApplicationContextAwareProcessor實現了BeanPostProcessor接口,根據javadoc這個類用來調用以下接口的回調方法:

1、EnvironmentAware

2、EmbeddedValueResolverAware

3、ResourceLoaderAware

3、ApplicationEventPublisherAware

4、MessageSourceAware

5、ApplicationContextAware

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

5、EventListenerMethodProcessor

6、PersistenceAnnotationBeanPostProcessor


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM