相关代码在: 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#run(Object source, String... args)
#L1174
SpringApplication(sources)
#L236
SpringApplication#initialize(Object[] sources)
#L256
javadoc
SpringApplication
使用source来构建Bean。一般来说在 run
的时候都会把 @SpringBootApplication
标记的类(本例中是SampleApplication)放到 sources
参数里,然后由这个类出发找到Bean的定义。 SpringApplication#run(args)
#L297
,进入运行阶段
SpringApplication#run(args)
#L297
SpringApplication#run(args)
#L297
-> #L308
-> prepareEnvironment(...)
#L331
准备 ConfigurableEnvironment
。
可以参考 官方文档 了解 StandardEnvironment 构建好之后,其 MutablePropertySources 内部到底有些啥东东。
SpringApplication#run(args)
#L297
SpringApplication#createApplicationContext()
#L583
创建 ApplicationContext
。可以看到实际上创建的是 AnnotationConfigApplicationContext
或 AnnotationConfigEmbeddedWebApplicationContext
。 SpringApplication#prepareContext(...)
#L344
准备 ApplicationContext
context.setEnvironment(environment)
,把之前准备好的 Environment
塞给 ApplicationContext
postProcessApplicationContext(context)
#L605
,给 ApplicationContext
设置了一些其他东西 applyInitializers(context)
#L630
,调用之前准备好的 ApplicationContextInitializer
listeners.contextPrepared(context)
-> EventPublishingRunListener.contextPrepared
,但实际上啥都没做。 load
#L687
,负责将source(复数)里所定义的Bean加载到 ApplicationContext
里,在本例中就是SampleApplication,这些source是在初始化SpringApplication阶段获得的。 listeners.contextLoaded(context)
-> EventPublishingRunListener.contextLoaded
。 要注意的是在这个阶段, ApplicationContext 里只有SampleApplication,SampleApplication是Bean的加载工作的起点。
根据前面所讲,这里的 ApplicationContext 实际上是 GenericApplicationContext -> AnnotationConfigApplicationContext 或者 AnnotationConfigEmbeddedWebApplicationContext
SpringApplication#run(args)
#L297
-> #L315
-> SpringApplication#refreshContext(context)
#L370
-> #L371
-> SpringApplication#refresh(context)
#L759
-> #L761
-> AbstractApplicationContext#refresh
AbstractApplicationContext#L507
AbstractApplicationContext#prepareRefresh()
#L575
,做了一些初始化工作,比如设置了当前Context的状态,初始化propertySource(其实啥都没干),检查required的property是否都已在Environment中(其实并没有required的property可供检查)等。 obtainFreshBeanFactory()
#L611
,获得 BeanFactory
,实际上这里获得的是 DefaultListableBeanFactory
prepareBeanFactory(beanFactory)
#L625
准备 BeanFactory
getEnvironment()
作为Bean添加到beanFactory中,Bean Name: environment
getEnvironment().getSystemProperties()
作为Bean添加到beanFactory中,Bean Name: systemProperties
getEnvironment().getSystemEnvironment()
作为Bean添加到beanFactory中,Bean Name: systemEnvironment
postProcessBeanFactory(beanFactory)
,后置处理 BeanFactory
,实际啥都没做 invokeBeanFactoryPostProcessors(beanFactory)
,利用 BeanFactoryPostProcessor
,对beanFactory做后置处理。调用此方法时有四个 BeanFactoryPostProcessor
: registerBeanPostProcessors(beanFactory)
,注册 BeanPostProcessor
initMessageSource()
#L704
,初始化 MessageSource
,不过其实此时的 MessageSource
是个Noop对象。 initApplicationEventMulticaster()
#L739
,初始化 ApplicationEventMulticaster
。 onRefresh()
#L793
,这个方法啥都没做 registerListeners()
#L801
,把自己的 ApplicationListener
注册到 ApplicationEventMulticaster
里,并且将之前因为没有 ApplicationEventMulticaster
而无法发出的 ApplicationEvent
发送出去。 finishBeanFactoryInitialization
#L828
。注意 #L861
,在这一步的时候才会实例化所有non-lazy-init bean,这里说的实例化不只是new而已,注入、 BeanPostProcessor
都会执行。 finishRefresh()
#L869
。
SpringApplication#run(args)
#L297
-> afterRefresh(context, applicationArguments)
#L316
-> callRunners(context, args)
#L771
-> #L774
先后调用了当前 ApplicationContext
中的 ApplicationRunner
和 CommandLineRunner
。关于它们的相关文档可以看 这里
。
需要注意的是,此时的 ApplicationContext 已经刷新完毕了,该有的Bean都已经有了。
SpringApplication#run(args)
#L297
-> listeners.finished(context, null)
#L317
间接地调用了 EventPublishingRunListener#getFinishedEvent
EventPublishingRunListener#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
已知清单2:spring-boot-autoconfigure-1.4.1.RELEASE.jar!/META-INF/spring.factories
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中定义的
已知清单2:spring-boot-autoconfigure-1.4.1.RELEASE.jar!/META-INF/spring.factories中定义的
javadoc
加载方式:读取 classpath*:META-INF/spring.factories
中key等于 org.springframework.boot.SpringApplicationRunListener
的property列出的类
排序方式: AnnotationAwareOrderComparator
已知清单:spring-boot-1.4.1.RELEASE.jar!/META-INF/spring.factories定义的
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定义的
javadoc 相关文档
用来对Bean实例进行修改的勾子,根据Javadoc ApplicationContext会自动侦测到BeanPostProcessor Bean,然后将它们应用到后续创建的所有Bean上。
相关文档
PostProcessorRegistrationDelegate 负责调用 BeanDefinitionRegistryPostProcessor 和 BeanFactoryPostProcessor 。 BeanDefinitionRegistryPostProcessor 在 BeanFactoryPostProcessor 之前被调用。
*Aware是一类可以用来获得Spring对象的interface,这些interface都继承了 Aware ,已知的有:
@Configuration 替代xml来定义 BeanDefinition 的一种手段。 Auto-configuration 也是定义 BeanDefinition 的一种手段。
这两者的相同之处有:
而不同之处有:
classpath*:META-INF/spring.factories
中key等于 org.springframework.boot.autoconfigure.EnableAutoConfiguration
的property列出的 @Configuration
加载的 以下情况下 Auto-configuration 会在普通 @Configuration 前加载:
参考 EnableAutoConfiguration 和附录 EnableAutoConfigurationImportSelector 了解Spring boot内部处理机制。
这个类用来读取 @Configuration 和 @Component ,并将 BeanDefinition 注册到 ApplicationContext 里。
ConfigurationClassPostProcessor 是一个 BeanDefinitionRegistryPostProcessor ,负责处理 @Configuration 。
需要注意一个烟雾弹:看 #L296 -> ConfigurationClassUtils#L209 。而order的值则是在 ConfigurationClassUtils#L122 从注解中提取的。 这段代码似乎告诉我们它会对 @Configuration 进行排序,然后按次序加载。 实际上不是的, @Configuration 是一个递归加载的过程。在本例中,是先从SampleApplication开始加载的,而事实上在这个时候,也就只有SampleApplication它自己可以提供排序。 而之后则直接使用了 ConfigurationClassParser ,它里面并没有排序的逻辑。
关于排序的方式简单来说是这样的: @Configuration 的排序根据且只根据 @Order 排序,如果没有 @Order 则优先级最低。
前面讲了 ConfigurationClassPostProcessor 使用 ConfigurationClassParser ,实际上加载 @Configuration 的工作是在这里做的。
下面讲以下加载的顺序:
那 Auto-configuration 在哪里呢? 实际上是在第3步里, @SpringBootApplication 存在注解 @EnableAutoConfiguration ,它使用了 EnableAutoConfigurationImportSelector , EnableAutoConfigurationImportSelector 是一个 DeferredImportSelector ,所以也就是说, Auto-configuration 是在普通 @Configuration 之后再加载的。
顺带一提,如果 Auto-configuration 里再使用 DeferredImportSelector ,那么效果和使用 ImportSelector 效果是一样的,不会再被延后处理。参见例子代码里的UselessDeferredImportSelectorAutoConfiguration。
EnableAutoConfigurationImportSelector 负责导入 Auto-configuration 。
它利用 AutoConfigurationSorter 对 Auto-configuration 进行排序。逻辑算法是:
LoggingApplicationListener 用来配置日志系统的,比如logback、log4j。Spring boot对于日志有 详细解释 ,如果你想 自定义日志配置 ,那么也请参考本文中对于 LoggingApplicationListener 的被调用时机的说明以获得更深入的了解。
StandardEnvironment 有一个 MutablePropertySources ,它里面有多个 PropertySource , PropertySource 负责提供property(即property的提供源),目前已知的 PropertySource 实现有: MapPropertySource 、 SystemEnvironmentPropertySource 、 CommandLinePropertySource 等。当 StandardEnvironment 查找property值的时候,是从 MutablePropertySources 里依次查找的,而且一旦查找到就不再查找,也就是说如果要覆盖property的值,那么就得提供顺序在前的 PropertySource 。
ConfigFileApplicationListener
用来将 application.properties
加载到 StandardEnvironment
中。
ConfigFileApplicationListener 内部使用了 EnvironmentPostProcessor (见附录)自定义 StandardEnvironment
ApplicationContextAwareProcessor 实现了 BeanPostProcessor 接口,根据javadoc这个类用来调用以下接口的回调方法:
根据 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 在其构造函数内部间接( AnnotationConfigUtils#L145 )的给 BeanFactory 注册了几个与 BeanDefinition 相关注解的处理器。