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

Spring Boot启动过程及回调接口汇总的更多相关文章

  1. Spring Boot启动过程(三)

    我已经很精简了,两篇(Spring Boot启动过程(一).pring Boot启动过程(二))依然没写完,接着来. refreshContext之后的方法是afterRefresh,这名字起的真.. ...

  2. Spring Boot启动过程(四):Spring Boot内嵌Tomcat启动

    之前在Spring Boot启动过程(二)提到过createEmbeddedServletContainer创建了内嵌的Servlet容器,我用的是默认的Tomcat. private void cr ...

  3. Spring Boot启动过程(七):Connector初始化

    Connector实例的创建已经在Spring Boot启动过程(四):Spring Boot内嵌Tomcat启动中提到了: Connector是LifecycleMBeanBase的子类,先是设置L ...

  4. Spring Boot 启动过程

    一切从SpringApplication.run()开始,最终返回一个ConfigurableApplicationContext 构造了一个SpringApplication对象,然后调用它的run ...

  5. Spring Boot启动过程(一)

    之前在排查一个线上问题时,不得不仔细跑了很多遍Spring Boot的代码,于是整理一下,我用的是1.4.3.RELEASE. 首先,普通的入口,这没什么好说的,我就随便贴贴代码了: SpringAp ...

  6. Spring Boot启动过程(二)

    书接上篇 该说refreshContext(context)了,首先是判断context是否是AbstractApplicationContext派生类的实例,之后调用了强转为AbstractAppl ...

  7. 转:Spring Boot启动过程

    之前在排查一个线上问题时,不得不仔细跑了很多遍Spring Boot的代码,于是整理一下,我用的是1.4.3.RELEASE. 首先,普通的入口,这没什么好说的,我就随便贴贴代码了: SpringAp ...

  8. Spring Boot 启动过程及 自定义 Listener等组件

    一.启动过程 二.自定义组件 package com.example.jdbc.listener; import org.springframework.context.ApplicationCont ...

  9. Spring boot 启动过程解析 logback

    使用 Spring Boot 默认的日志框架 Logback. 所有这些 POM 依赖的好处在于为开发 Spring 应用提供了一个良好的基础.Spring Boot 所选择的第三方库是经过考虑的,是 ...

随机推荐

  1. Volume Shadow Copy Service(VSS)如何工作

    VSS卷影拷贝服务其实不是一项新技术了,在2003年前后发布的Windows 2003和Windows XP SP1都提供了对VSS的支持.最近几年微软的一线产品对VSS支持的越来越多,包括Excha ...

  2. iPad Air 2全然评測:可怕的三核CPU、六核GPU

    在了解了三核心A8X的基本情况后.我们再来通过測试数据,全面地了解一下iPad Air 2的性能表现,包含CPU.GPU.存储.电池.屏幕.摄像头.导航等等. [CPU性能測试:三核太可怕了] 移动处 ...

  3. Java中经常使用缓存Cache机制的实现

    缓存,就是将程序或系统常常要调用的对象存在内存中,一遍其使用时能够高速调用,不必再去创建新的反复的实例. 这样做能够降低系统开销.提高系统效率. 缓存主要可分为二大类: 一.通过文件缓存,顾名思义文件 ...

  4. Java多线程之Future与FutureTask

    转载请注明原文地址:http://www.cnblogs.com/ygj0930/p/6561154.html  一:Future 在使用实现Callable创建线程时,call()方法是有返回值的. ...

  5. JSFL 获取当前脚本路径,执行其他脚本

    Application.jsfl为程序入口,导入其他jsfl [Common.jsfl] function trace() { fl.trace(Array.prototype.join.call(a ...

  6. 取某字段不为空的数据is not null

    SELECT * FROM 表名  where  uid='xxx'  and  time  is not null

  7. 三种分布式对象主流技术——COM、Java和COBRA

    既上一遍,看到还有一遍将关于 对象的, 分布式对象, 故摘抄入下: 目前国际上,分布式对象技术有三大流派——COBRA.COM/DCOM和Java.CORBA技术是最早出现的,1991年OMG颁布了C ...

  8. javascript判断是否按回车键

    function enterHandler(event){ var keyCode = event.keyCode ? event.keyCode : event.which ? event.whic ...

  9. Textview文字监控(输入到某个字符后,进行操作)

      以手机号充值为例,当用户输入最后一位数时候,进行汇率的变换.   1.首先给用户添加一个textchangedlistener   2.然后再写一个文字变化的监视器   mobile_et.add ...

  10. 完善_IO, _IOR, _IOW, _IOWR 宏的用法与解析

    _IO, _IOR, _IOW, _IOWR 宏的用法与解析  原文地址:http://www.eefocus.com/ayayayaya/blog/12-03/245777_20cdd.html 作 ...