转载

Spring Boot 启动过程及回调接口汇总

相关代码在: https://github.com/chanjarster/spring-boot-all-callbacks

注:本文基于 spring-boot 1.4.1.RELEASE ,  spring 4.3.3.RELEASE 撰写。

启动顺序

Spring boot的启动代码一般是这样的:

@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:
    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:
  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 。可以看到实际上创建的是 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

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 负责调用 BeanDefinitionRegistryPostProcessor 和 BeanFactoryPostProcessor 。 BeanDefinitionRegistryPostProcessor 在 BeanFactoryPostProcessor 之前被调用。

*Aware

*Aware是一类可以用来获得Spring对象的interface,这些interface都继承了 Aware ,已知的有:

  • ApplicationEventPublisherAware
  • NotificationPublisherAware
  • MessageSourceAware
  • EnvironmentAware
  • BeanFactoryAware
  • EmbeddedValueResolverAware
  • ResourceLoaderAware
  • ImportAware
  • LoadTimeWeaverAware
  • BeanNameAware
  • BeanClassLoaderAware
  • ApplicationContextAware

@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. 内部加载顺序可控上的不同:
    • 普通 @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这个类用来调用以下接口的回调方法:

  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 相关注解的处理器。

原文  http://www.importnew.com/27511.html
正文到此结束
Loading...