摘要:创建及准备创建。目前已知关心这个事件的有要注意的是在这个阶段,里只有,是的加载工作的起点。原因是注入这些回调接口本身没有什么意义。在其构造函数内部间接的给注册了几个与相关注解的处理器。
相关代码在: 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
SpringApplication#run(Object source, String... args)#L1174
SpringApplication#L1186 -> SpringApplication(sources)#L236
SpringApplication#initialize(Object[] sources)#L256 javadoc
SpringApplication#L257 添加source(复数),SpringApplication使用source来构建Bean。一般来说在run的时候都会把@SpringBootApplication标记的类(本例中是SampleApplication)放到sources参数里,然后由这个类出发找到Bean的定义。
SpringApplication#L261 初始化ApplicationContextInitializer列表(见附录)
SpringApplication#L263 初始化ApplicationListener列表(见附录)
SpringApplication#L1186 -> SpringApplication#run(args)#L297,进入运行阶段
推送ApplicationStartedEventSpringApplication#run(args)#L297
SpringApplication#L303 初始化SpringApplicationRunListeners (SpringApplicationRunListener的集合)。它内部只包含EventPublishingRunListener。
SpringApplication#L304 推送ApplicationStartedEvent给所有的ApplicationListener(见附录)。 下面是关心此事件的listener:
LiquibaseServiceLocatorApplicationListener
LoggingApplicationListener(见附录)
准备EnvironmentSpringApplication#run(args)#L297->#L308->prepareEnvironment(...)#L331准备ConfigurableEnvironment。
SpringApplication#L335 创建StandardEnvironment(见附录)。
SpringApplication#L336 配置StandardEnvironment,将命令行和默认参数整吧整吧,添加到MutablePropertySources。
SpringApplication#L337 推送ApplicationEnvironmentPreparedEvent给所有的ApplicationListener(见附录)。下面是关心此事件的listener:
BackgroundPreinitializer
FileEncodingApplicationListener
AnsiOutputApplicationListener
ConfigFileApplicationListener(见附录)
DelegatingApplicationListener
ClasspathLoggingApplicationListener
LoggingApplicationListener
ApplicationPidFileWriter
可以参考官方文档了解StandardEnvironment构建好之后,其MutablePropertySources内部到底有些啥东东。
创建及准备ApplicationContextSpringApplication#run(args)#L297
SpringApplication#L311->SpringApplication#createApplicationContext()#L583创建ApplicationContext。可以看到实际上创建的是AnnotationConfigApplicationContext或AnnotationConfigEmbeddedWebApplicationContext。
在构造AnnotationConfigApplicationContext的时候,间接注册了一个BeanDefinitionRegistryPostProcessor的Bean:ConfigurationClassPostProcessor。经由AnnotatedBeanDefinitionReader构造函数->AnnotationConfigUtils.registerAnnotationConfigProcessors。
SpringApplication#L313->SpringApplication#prepareContext(...)#L344准备ApplicationContext
SpringApplication#L347->context.setEnvironment(environment),把之前准备好的Environment塞给ApplicationContext
SpringApplication#L348->postProcessApplicationContext(context)#L605,给ApplicationContext设置了一些其他东西
SpringApplication#L349->applyInitializers(context)#L630,调用之前准备好的ApplicationContextInitializer
SpringApplication#L350->listeners.contextPrepared(context)->EventPublishingRunListener.contextPrepared,但实际上啥都没做。
SpringApplication#L366->load#L687,负责将source(复数)里所定义的Bean加载到ApplicationContext里,在本例中就是SampleApplication,这些source是在初始化SpringApplication阶段获得的。
SpringApplication#L367->listeners.contextLoaded(context)->EventPublishingRunListener.contextLoaded。
将SpringApplication自己拥有的ApplicationListener加入到ApplicationContext
发送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#refreshAbstractApplicationContext#L507
AbstractApplicationContext#L510->AbstractApplicationContext#prepareRefresh()#L575,做了一些初始化工作,比如设置了当前Context的状态,初始化propertySource(其实啥都没干),检查required的property是否都已在Environment中(其实并没有required的property可供检查)等。
AbstractApplicationContext#L513->obtainFreshBeanFactory()#L611,获得BeanFactory,实际上这里获得的是DefaultListableBeanFactory
AbstractApplicationContext#L516->prepareBeanFactory(beanFactory)#L625准备BeanFactory
给beanFactory设置了ClassLoader
给beanFactory设置了SpEL解析器
给beanFactory设置了PropertyEditorRegistrar
给beanFactory添加了ApplicationContextAwareProcessor(BeanPostProcessor的实现类),需要注意的是它是第一个被添加到BeanFactory的BeanPostProcessor
给beanFactory设置忽略解析以下类的依赖:ResourceLoaderAware、ApplicationEventPublisherAware、MessageSourceAware、ApplicationContextAware、EnvironmentAware。原因是注入这些回调接口本身没有什么意义。
给beanFactory添加了以下类的依赖解析:BeanFactory、ResourceLoader、ApplicationEventPublisher、ApplicationContext
给beanFactory添加LoadTimeWeaverAwareProcessor用来处理LoadTimeWeaverAware的回调,在和AspectJ集成的时候会用到
把getEnvironment()作为Bean添加到beanFactory中,Bean Name: environment
把getEnvironment().getSystemProperties()作为Bean添加到beanFactory中,Bean Name: systemProperties
把getEnvironment().getSystemEnvironment()作为Bean添加到beanFactory中,Bean Name: systemEnvironment
AbstractApplicationContext#L520->postProcessBeanFactory(beanFactory),后置处理BeanFactory,实际啥都没做
AbstractApplicationContext#L523->invokeBeanFactoryPostProcessors(beanFactory),利用BeanFactoryPostProcessor,对beanFactory做后置处理。调用此方法时有四个BeanFactoryPostProcessor:
SharedMetadataReaderFactoryContextInitializer的内部类CachingMetadataReaderFactoryPostProcessor,是在 创建及准备ApplicationContext 2.3 时添加的:#L57
ConfigurationWarningsApplicationContextInitializer的内部类ConfigurationWarningsPostProcessor,是在 创建及准备ApplicationContext 2.3 时添加的:#L60
ConfigFileApplicationListener的内部类PropertySourceOrderingPostProcessor,是在 创建及准备ApplicationContext 2.6 时添加的:#L158->#L199->#L244
ConfigurationClassPostProcessor,负责读取BeanDefinition是在 创建及准备ApplicationContext 1.1 时添加的
AbstractApplicationContext#L526->registerBeanPostProcessors(beanFactory),注册BeanPostProcessor
AbstractApplicationContext#L529->initMessageSource()#L704,初始化MessageSource,不过其实此时的MessageSource是个Noop对象。
AbstractApplicationContext#L532->initApplicationEventMulticaster()#L739,初始化ApplicationEventMulticaster。
AbstractApplicationContext#L535->onRefresh()#L793,这个方法啥都没做
AbstractApplicationContext#L538->registerListeners()#L801,把自己的ApplicationListener注册到ApplicationEventMulticaster里,并且将之前因为没有ApplicationEventMulticaster而无法发出的ApplicationEvent发送出去。
AbstractApplicationContext#L541->finishBeanFactoryInitialization#L828。注意#L861,在这一步的时候才会实例化所有non-lazy-init bean,这里说的实例化不只是new而已,注入、BeanPostProcessor都会执行。
AbstractApplicationContext#L544->finishRefresh()#L869。
在#L877发送了ContextRefreshedEvent
调用 ApplicationRunner 和 CommandLineRunnerSpringApplication#run(args)#L297
->afterRefresh(context, applicationArguments)#L316
->callRunners(context, args)#L771
->#L774 先后调用了当前ApplicationContext中的ApplicationRunner和CommandLineRunner。关于它们的相关文档可以看这里。
需要注意的是,此时的ApplicationContext已经刷新完毕了,该有的Bean都已经有了。
推送ApplicationReadyEvent or ApplicationFailedEventSpringApplication#run(args)#L297->listeners.finished(context, null)#L317
间接地调用了EventPublishingRunListener#getFinishedEventEventPublishingRunListener#L96,发送了ApplicationReadyEvent或ApplicationFailedEvent
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
ConfigurationWarningsApplicationContextInitializer(优先级:0)
ContextIdApplicationContextInitializer(优先级:Ordered.LOWEST_PRECEDENCE - 10)
DelegatingApplicationContextInitializer(优先级:无=Ordered.LOWEST_PRECEDENCE)
ServerPortInfoApplicationContextInitializer(优先级:无=Ordered.LOWEST_PRECEDENCE)
已知清单2:spring-boot-autoconfigure-1.4.1.RELEASE.jar!/META-INF/spring.factories
SharedMetadataReaderFactoryContextInitializer(优先级:无=Ordered.LOWEST_PRECEDENCE)
AutoConfigurationReportLoggingInitializer(优先级:无=Ordered.LOWEST_PRECEDENCE)
ApplicationListenerjavadoc 相关文档
加载方式:读取classpath*:META-INF/spring.factories中key等于org.springframework.context.ApplicationListener的property列出的类
排序方式:AnnotationAwareOrderComparator
已知清单1:spring-boot-1.4.1.RELEASE.jar!/META-INF/spring.factories中定义的
ClearCachesApplicationListener(优先级:无=Ordered.LOWEST_PRECEDENCE)
ParentContextCloserApplicationListener(优先级:Ordered.LOWEST_PRECEDENCE - 10)
FileEncodingApplicationListener(优先级:Ordered.LOWEST_PRECEDENCE)
AnsiOutputApplicationListener(优先级:ConfigFileApplicationListener.DEFAULT_ORDER + 1)
ConfigFileApplicationListener(优先级:Ordered.HIGHEST_PRECEDENCE + 10)
DelegatingApplicationListener(优先级:0)
LiquibaseServiceLocatorApplicationListener(优先级:无=Ordered.LOWEST_PRECEDENCE)
ClasspathLoggingApplicationListener(优先级:LoggingApplicationListener的优先级 + 1)
LoggingApplicationListener(优先级:Ordered.HIGHEST_PRECEDENCE + 20)
已知清单2:spring-boot-autoconfigure-1.4.1.RELEASE.jar!/META-INF/spring.factories中定义的
BackgroundPreinitializer
SpringApplicationRunListenerjavadoc
加载方式:读取classpath*:META-INF/spring.factories中key等于org.springframework.boot.SpringApplicationRunListener的property列出的类
排序方式:AnnotationAwareOrderComparator
已知清单:spring-boot-1.4.1.RELEASE.jar!/META-INF/spring.factories定义的
org.springframework.boot.context.event.EventPublishingRunListener(优先级:0)
EnvironmentPostProcessorEnvironmentPostProcessor可以用来自定义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定义的
CloudFoundryVcapEnvironmentPostProcessor(优先级:ConfigFileApplicationListener.DEFAULT_ORDER - 1)
SpringApplicationJsonEnvironmentPostProcessor(优先级:Ordered.HIGHEST_PRECEDENCE + 5)
BeanPostProcessorjavadoc 相关文档
用来对Bean实例进行修改的勾子,根据Javadoc ApplicationContext会自动侦测到BeanPostProcessor Bean,然后将它们应用到后续创建的所有Bean上。
BeanFactoryPostProcessor和BeanDefinitionRegistryPostProcessor相关文档
PostProcessorRegistrationDelegate负责调用BeanDefinitionRegistryPostProcessor和BeanFactoryPostProcessor。
BeanDefinitionRegistryPostProcessor在BeanFactoryPostProcessor之前被调用。
*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的一种手段。
这两者的相同之处有:
都是使用@Configuration注解的类,这些类里都可以定义@Bean、@Import、@ImportResource。
都可以使用@Condition*来根据情况选择是否加载
而不同之处有:
加载方式不同:
普通@Configuration则是通过扫描package path加载的
Auto-configuration的是通过读取classpath*:META-INF/spring.factories中key等于org.springframework.boot.autoconfigure.EnableAutoConfiguration的property列出的@Configuration加载的
加载顺序不同:普通@Configuration的加载永远在Auto-configuration之前
内部加载顺序可控上的不同:
普通@Configuration则无法控制加载顺序
Auto-configuration可以使用@AutoConfigureOrder、@AutoConfigureBefore、@AutoConfigureAfter
以下情况下Auto-configuration会在普通@Configuration前加载:
Auto-configuration如果出现在最初的扫描路径里(@ComponentScan),就会被提前加载到,然后被当作普通的@Configuration处理,这样@AutoConfigureBefore和@AutoConfigureAfter就没用了。参看例子代码里的InsideAutoConfiguration和InsideAutoConfiguration2。
Auto-configuration如果提供BeanPostProcessor,那么它会被提前加载。参见例子代码里的BeanPostProcessorAutoConfiguration。
Auto-configuration如果使用了ImportBeanDefinitionRegistrar,那么ImportBeanDefinitionRegistrar会被提前加载。参见例子代码里的ImportBeanDefinitionRegistrarAutoConfiguration。
Auto-configuration如果使用了ImportSelector,那么ImportSelector会被提前加载。参见例子代码里的UselessDeferredImportSelectorAutoConfiguration。
参考EnableAutoConfiguration和附录EnableAutoConfigurationImportSelector了解Spring boot内部处理机制
AnnotatedBeanDefinitionReader这个类用来读取@Configuration和@Component,并将BeanDefinition注册到ApplicationContext里。
ConfigurationClassPostProcessorConfigurationClassPostProcessor是一个BeanDefinitionRegistryPostProcessor,负责处理@Configuration。
需要注意一个烟雾弹:看#L296->ConfigurationClassUtils#L209。而order的值则是在ConfigurationClassUtils#L122从注解中提取的。
这段代码似乎告诉我们它会对@Configuration进行排序,然后按次序加载。
实际上不是的,@Configuration是一个递归加载的过程。在本例中,是先从SampleApplication开始加载的,而事实上在这个时候,也就只有SampleApplication它自己可以提供排序。
而之后则直接使用了ConfigurationClassParser,它里面并没有排序的逻辑。
关于排序的方式简单来说是这样的:@Configuration的排序根据且只根据@Order排序,如果没有@Order则优先级最低。
ConfigurationClassParser前面讲了ConfigurationClassPostProcessor使用ConfigurationClassParser,实际上加载@Configuration的工作是在这里做的。
下面讲以下加载的顺序:
以SampleApplication为起点开始扫描
扫描得到所有的@Configuration和@Component,从中读取BeanDefinition并导入:
如果@Configuration注解了@Import
如果使用的是ImportSelector,则递归导入
如果使用的是ImportBeanDefinitionRegistrar,则递归导入
如果使用的是DeferredImportSelector,则仅收集不导入
如果@Configuration注解了@ImportResource,则递归导入
迭代之前收集的DeferredImportSelector,递归导入
那Auto-configuration在哪里呢?
实际上是在第3步里,@SpringBootApplication存在注解@EnableAutoConfiguration,它使用了EnableAutoConfigurationImportSelector,
EnableAutoConfigurationImportSelector是一个DeferredImportSelector,所以也就是说,Auto-configuration是在普通@Configuration之后再加载的。
顺带一提,如果Auto-configuration里再使用DeferredImportSelector,那么效果和使用ImportSelector效果是一样的,不会再被延后处理。参见例子代码里的UselessDeferredImportSelectorAutoConfiguration。
EnableAutoConfigurationImportSelectorEnableAutoConfigurationImportSelector负责导入Auto-configuration。
它利用AutoConfigurationSorter对Auto-configuration进行排序。逻辑算法是:
先根据类名排序
再根据@AutoConfigureOrder排序,如果没有@AutoConfigureOrder则优先级最低
再根据@AutoConfigureBefore,@AutoConfigureAfter排序
内置类说明 LoggingApplicationListenerLoggingApplicationListener用来配置日志系统的,比如logback、log4j。Spring boot对于日志有详细解释,如果你想自定义日志配置,那么也请参考本文中对于LoggingApplicationListener的被调用时机的说明以获得更深入的了解。
StandardEnvironmentStandardEnvironment有一个MutablePropertySources,它里面有多个PropertySource,PropertySource负责提供property(即property的提供源),目前已知的PropertySource实现有:MapPropertySource、SystemEnvironmentPropertySource、CommandLinePropertySource等。当StandardEnvironment查找property值的时候,是从MutablePropertySources里依次查找的,而且一旦查找到就不再查找,也就是说如果要覆盖property的值,那么就得提供顺序在前的PropertySource。
ConfigFileApplicationListenerConfigFileApplicationListener用来将application.properties加载到StandardEnvironment中。
ConfigFileApplicationListener内部使用了EnvironmentPostProcessor(见附录)自定义StandardEnvironment
ApplicationContextAwareProcessorApplicationContextAwareProcessor实现了BeanPostProcessor接口,根据javadoc这个类用来调用以下接口的回调方法:
EnvironmentAware
EmbeddedValueResolverAware
ResourceLoaderAware
ApplicationEventPublisherAware
MessageSourceAware
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。
AnnotatedBeanDefinitionReaderAnnotatedBeanDefinitionReader在其构造函数内部间接(AnnotationConfigUtils#L145)的给BeanFactory注册了几个与BeanDefinition相关注解的处理器。
ConfigurationClassPostProcessor
AutowiredAnnotationBeanPostProcessor
RequiredAnnotationBeanPostProcessor
CommonAnnotationBeanPostProcessor
EventListenerMethodProcessor
PersistenceAnnotationBeanPostProcessor
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/66039.html
摘要:在一个初春的下午,甲跟我说,要在启动服务的时候,设置表自增的起始值。写完启动项,那么再把退出也说一下每一个都应该向注册一个钩子函数来确保能优雅地关闭。后面退出部分翻译地磕磕碰碰的,有不对的地方欢迎指正。原创不易,感谢支持。 在一个初春的下午,甲跟我说,要在Spring Boot启动服务的时候,设置表自增的起始值。于是我用屁股想了一下,不就是在main方法里折腾嘛。后来实际操作了一把,发...
摘要:代码示例本文示例读者可以通过查看下面仓库的中的三个项目如果您对这些感兴趣,欢迎收藏转发给予支持以下专题教程也许您会有兴趣基础教程基础教程 有很多读者问过这样的一个问题:虽然使用Swagger可以为Spring MVC编写的接口生成了API文档,但是在微服务化之后,这些API文档都离散在各个微服务中,是否有办法将这些接口都整合到一个文档中?之前给大家的回复都只是简单的说了个思路,昨天正好...
摘要:总结基于构建相对来说还是比较便捷的,其中注解使得代码更加简洁,本次用到注解再汇总下,有时间的话可以深入理解下其背后的原理申明让自动给程序进行必要的配置。风格的控制器提供路由信息,负责到中的具体函数的映射一般用于修饰层的组件自动导入依赖的 本文主要记录搭建RESTful API标准工程,包含比较推荐的工程结构,掌握一些基本注解,并引入Swagger 新建一个项目 通过Spring Ini...
摘要:实例定义一个实现,并纳入到容器中进行处理启动定义一个实现,并纳入到容器处理应用已经成功启动启动类测试,也可以直接在容器访问该值,配置参数,然后执行启动类打印结果接口发现二者的官方一样,区别在于接收的参数不一样。引言 我们在使用SpringBoot搭建项目的时候,如果希望在项目启动完成之前,能够初始化一些操作,针对这种需求,可以考虑实现如下两个接口(任一个都可以) org.springfram...
摘要:除了,还有十余种,有的是特定操作,比如转储内存日志有的是信息展示,比如显示应用健康状态。 showImg(http://ww1.sinaimg.cn/large/006tNc79gy1g5qb2coyfoj30u00k0tan.jpg); 前言 随着线上应用逐步采用 SpringBoot 构建,SpringBoot应用实例越来多,当线上某个应用需要升级部署时,常常简单粗暴地使用 kil...
阅读 3894·2021-09-09 09:33
阅读 1734·2021-09-06 15:14
阅读 1896·2019-08-30 15:44
阅读 3044·2019-08-29 18:36
阅读 3732·2019-08-29 16:22
阅读 2073·2019-08-29 16:21
阅读 2492·2019-08-29 15:42
阅读 1629·2019-08-29 11:00