Spring Boot啓動過程及回調接口彙總

相關代碼在: https://github.com/chanjarster/spring-boot-all-callbackshtml

注:本文基於spring-boot 1.4.1.RELEASE, spring 4.3.3.RELEASE撰寫。java

啓動順序

Spring boot的啓動代碼通常是這樣的:git

@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)#L1174github

  2. SpringApplication#L1186 -> SpringApplication(sources)#L236web

    1. SpringApplication#initialize(Object[] sources)#L256 javadoc算法

      1. SpringApplication#L257 添加source(複數),SpringApplication使用source來構建Bean。通常來講在run的時候都會把@SpringBootApplication標記的類(本例中是SampleApplication)放到sources參數裏,而後由這個類出發找到Bean的定義。spring

      2. SpringApplication#L261 初始化ApplicationContextInitializer列表(見附錄)express

      3. SpringApplication#L263 初始化ApplicationListener列表(見附錄)api

  3. SpringApplication#L1186 -> SpringApplication#run(args)#L297,進入運行階段app

推送ApplicationStartedEvent

SpringApplication#run(args)#L297

  1. SpringApplication#L303 初始化SpringApplicationRunListeners (SpringApplicationRunListener的集合)。它內部只包含EventPublishingRunListener

  2. SpringApplication#L304 推送ApplicationStartedEvent給全部的ApplicationListener(見附錄)。 下面是關心此事件的listener:

    1. LiquibaseServiceLocatorApplicationListener

    2. LoggingApplicationListener(見附錄)

準備Environment

SpringApplication#run(args)#L297->#L308->prepareEnvironment(...)#L331準備ConfigurableEnvironment

  1. SpringApplication#L335 建立StandardEnvironment(見附錄)。

  2. SpringApplication#L336 配置StandardEnvironment,將命令行和默認參數整吧整吧,添加到MutablePropertySources

  3. SpringApplication#L337 推送ApplicationEnvironmentPreparedEvent給全部的ApplicationListener(見附錄)。下面是關心此事件的listener:

    1. BackgroundPreinitializer

    2. FileEncodingApplicationListener

    3. AnsiOutputApplicationListener

    4. ConfigFileApplicationListener(見附錄)

    5. DelegatingApplicationListener

    6. ClasspathLoggingApplicationListener

    7. LoggingApplicationListener

    8. ApplicationPidFileWriter

能夠參考官方文檔瞭解StandardEnvironment構建好以後,其MutablePropertySources內部到底有些啥東東。

建立及準備ApplicationContext

SpringApplication#run(args)#L297

  1. SpringApplication#L311->SpringApplication#createApplicationContext()#L583建立ApplicationContext。能夠看到實際上建立的是AnnotationConfigApplicationContextAnnotationConfigEmbeddedWebApplicationContext

    1. 在構造AnnotationConfigApplicationContext的時候,間接註冊了一個BeanDefinitionRegistryPostProcessor的Bean:ConfigurationClassPostProcessor。經由AnnotatedBeanDefinitionReader構造函數->AnnotationConfigUtils.registerAnnotationConfigProcessors

  2. SpringApplication#L313->SpringApplication#prepareContext(...)#L344準備ApplicationContext

    1. SpringApplication#L347->context.setEnvironment(environment),把以前準備好的Environment塞給ApplicationContext

    2. SpringApplication#L348->postProcessApplicationContext(context)#L605,給ApplicationContext設置了一些其餘東西

    3. SpringApplication#L349->applyInitializers(context)#L630,調用以前準備好的ApplicationContextInitializer

    4. SpringApplication#L350->listeners.contextPrepared(context)->EventPublishingRunListener.contextPrepared,但實際上啥都沒作。

    5. SpringApplication#L366->load#L687,負責將source(複數)裏所定義的Bean加載到ApplicationContext裏,在本例中就是SampleApplication,這些source是在初始化SpringApplication階段得到的。

    6. SpringApplication#L367->listeners.contextLoaded(context)->EventPublishingRunListener.contextLoaded

      1. SpringApplication本身擁有的ApplicationListener加入到ApplicationContext

      2. 發送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

    1. 給beanFactory設置了ClassLoader

    2. 給beanFactory設置了SpEL解析器

    3. 給beanFactory設置了PropertyEditorRegistrar

    4. 給beanFactory添加了ApplicationContextAwareProcessorBeanPostProcessor的實現類),須要注意的是它是第一個被添加到BeanFactoryBeanPostProcessor

    5. 給beanFactory設置忽略解析如下類的依賴:ResourceLoaderAwareApplicationEventPublisherAwareMessageSourceAwareApplicationContextAwareEnvironmentAware。緣由是注入這些回調接口自己沒有什麼意義。

    6. 給beanFactory添加了如下類的依賴解析:BeanFactoryResourceLoaderApplicationEventPublisherApplicationContext

    7. 給beanFactory添加LoadTimeWeaverAwareProcessor用來處理LoadTimeWeaverAware的回調,在和AspectJ集成的時候會用到

    8. getEnvironment()做爲Bean添加到beanFactory中,Bean Name: environment

    9. getEnvironment().getSystemProperties()做爲Bean添加到beanFactory中,Bean Name: systemProperties

    10. getEnvironment().getSystemEnvironment()做爲Bean添加到beanFactory中,Bean Name: systemEnvironment

  4. AbstractApplicationContext#L520->postProcessBeanFactory(beanFactory),後置處理BeanFactory,實際啥都沒作

  5. AbstractApplicationContext#L523->invokeBeanFactoryPostProcessors(beanFactory),利用BeanFactoryPostProcessor,對beanFactory作後置處理。調用此方法時有四個BeanFactoryPostProcessor

    1. SharedMetadataReaderFactoryContextInitializer的內部類CachingMetadataReaderFactoryPostProcessor,是在 建立及準備ApplicationContext 2.3 時添加的:#L57

    2. ConfigurationWarningsApplicationContextInitializer的內部類ConfigurationWarningsPostProcessor,是在 建立及準備ApplicationContext 2.3 時添加的:#L60

    3. ConfigFileApplicationListener的內部類PropertySourceOrderingPostProcessor,是在 建立及準備ApplicationContext 2.6 時添加的:#L158->#L199->#L244

    4. ConfigurationClassPostProcessor,負責讀取BeanDefinition是在 建立及準備ApplicationContext 1.1 時添加的

  6. AbstractApplicationContext#L526->registerBeanPostProcessors(beanFactory),註冊BeanPostProcessor

  7. AbstractApplicationContext#L529->initMessageSource()#L704,初始化MessageSource,不過其實此時的MessageSource是個Noop對象。

  8. AbstractApplicationContext#L532->initApplicationEventMulticaster()#L739,初始化ApplicationEventMulticaster

  9. AbstractApplicationContext#L535->onRefresh()#L793,這個方法啥都沒作

  10. AbstractApplicationContext#L538->registerListeners()#L801,把本身的ApplicationListener註冊到ApplicationEventMulticaster裏,而且將以前由於沒有ApplicationEventMulticaster而沒法發出的ApplicationEvent發送出去。

  11. AbstractApplicationContext#L541->finishBeanFactoryInitialization#L828。注意#L861,在這一步的時候纔會實例化全部non-lazy-init bean,這裏說的實例化不僅是new而已,注入、BeanPostProcessor都會執行。

  12. AbstractApplicationContext#L544->finishRefresh()#L869

    1. #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中定義的

  1. 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負責調用BeanDefinitionRegistryPostProcessorBeanFactoryPostProcessor
BeanDefinitionRegistryPostProcessorBeanFactoryPostProcessor以前被調用。

*Aware

*Aware是一類能夠用來得到Spring對象的interface,這些interface都繼承了Aware,已知的有:

@Configuration 和 Auto-configuration

@Configuration替代xml來定義BeanDefinition的一種手段。Auto-configuration也是定義BeanDefinition的一種手段。

這二者的相同之處有:

  1. 都是使用@Configuration註解的類,這些類裏均可以定義@Bean@Import@ImportResource

  2. 均可以使用@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並導入:

    1. 若是@Configuration註解了@Import

      1. 若是使用的是ImportSelector,則遞歸導入

      2. 若是使用的是ImportBeanDefinitionRegistrar,則遞歸導入

      3. 若是使用的是DeferredImportSelector,則僅收集不導入

    2. 若是@Configuration註解了@ImportResource,則遞歸導入

  3. 迭代以前收集的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

  4. ApplicationEventPublisherAware

  5. MessageSourceAware

  6. 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

相關文章
相關標籤/搜索