• Stars
    star
    175
  • Rank 218,059 (Top 5 %)
  • Language
    HTML
  • Created about 8 years ago
  • Updated over 6 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Spring boot回调接口汇总

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 1. SpringApplication#L257 添加source(复数),SpringApplication使用source来构建Bean。一般来说在run的时候都会把@SpringBootApplication标记的类(本例中是SampleApplication)放到sources参数里,然后由这个类出发找到Bean的定义。 2. SpringApplication#L261 初始化ApplicationContextInitializer列表(见附录) 3. SpringApplication#L263 初始化ApplicationListener列表(见附录)
  4. 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。可以看到实际上创建的是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。 1. 将SpringApplication自己拥有的ApplicationListener加入到ApplicationContext 1. 发送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中定义的

  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负责调用BeanDefinitionRegistryPostProcessorBeanFactoryPostProcessorBeanDefinitionRegistryPostProcessorBeanFactoryPostProcessor之前被调用。

*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并导入:
  3. 如果@Configuration注解了@Import 1. 如果使用的是ImportSelector,则递归导入 1. 如果使用的是ImportBeanDefinitionRegistrar,则递归导入 1. 如果使用的是DeferredImportSelector,则仅收集不导入
  4. 如果@Configuration注解了@ImportResource,则递归导入
  5. 迭代之前收集的DeferredImportSelector,递归导入

Auto-configuration在哪里呢? 实际上是在第3步里,@SpringBootApplication存在注解@EnableAutoConfiguration,它使用了EnableAutoConfigurationImportSelectorEnableAutoConfigurationImportSelector是一个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

More Repositories

1

weixin-java-tools

微信公众号、企业号Java SDK
Java
2,745
star
2

artemis-disruptor-miaosha

没有redis也能够支撑"小米在印度把亚马逊搞挂了"事件的秒杀解决方案
Java
617
star
3

spring-test-examples

Spring、Spring Boot和TestNG测试指南
Java
299
star
4

spring-mvc-error-handling-example

Spring MVC error handling example
Java
74
star
5

activiti-learn

Activiti样例代码集合
Java
63
star
6

transactions

关于各种Transaction解决方案的介绍
43
star
7

web-async-learn

Java web开发async机制学习
Java
36
star
8

prometheus-learn

学习Prometheus
Shell
26
star
9

dockerfile-examples

制作docker image的例子
Java
26
star
10

tomcat-mongo-access-log

A tomcat plugin saving access log to mongodb
Java
21
star
11

kubebuilder-mix-codegen-how-to

Mix kubebuilder and code-generator example
Go
21
star
12

k8s-learn

k8s learn
20
star
13

springboot-jackson-datetime-example

Spring Boot Jackson对于日期时间类型处理的例子
Java
16
star
14

prometheus-mock-data

A tool to generating prometheus mock scrape data
Java
16
star
15

spring-boot-istio-jaeger-demo

Spring Boot项目利用Istio的Jaeger做分布式Tracing的例子
Java
15
star
16

api-gateways-comparison

API Gateways' library comparison
HTML
11
star
17

mysql-master-slave-docker-example

10
star
18

spring-tx-learn

Spring transaction learn
Java
10
star
19

spring-jms-learn

Spring JMS学习
Java
8
star
20

networking-for-programmer

面向程序员的网络基本知识
6
star
21

tomcat-mongo-access-log-console

Console for querying tomcat access log saved in mongodb
JavaScript
5
star
22

spring-boot-redis-sentinel-example

Java
5
star
23

java-remote-debug-and-monitor

Java远程Debug及Monitor的例子
Java
4
star
24

arts

每周一个Algorithm、Review一篇英文文章、一个技术Tip、Share一个观点
Java
3
star
25

mybatis-learn

学习mybatis的小项目
Java
3
star
26

autoconf

A simple tool to parse yaml, env and flags to structs
2
star
27

io-modes-benchmark

不同IO模式的benchmark
Java
2
star
28

kafka-learn

Learning kafka
Java
2
star
29

gears

A Go microservice toolbox
Go
2
star
30

k8s-code-gen-how-to

How to use k8s.io/code-generator
Go
2
star
31

jdbc-timezone

研究JDBC对于数据库Timezone处理的例子
Java
2
star
32

tencent-pvp-equipment-simulator

王者荣耀出装模拟器
CSS
1
star
33

licai

Jupyter Notebook
1
star
34

chanjarster.github.io

My Blog
HTML
1
star
35

java-concurrency-learn

java concurrency program learn
Java
1
star
36

tls-client-auth-samples

TLS Client Authentication Client & Server Samples
Java
1
star