启动流程
| 1 | 
 | 
首先从启动类开始看起,main() 方法很简单,调用 SpringApplication 的静态方法run()。
| 1 | public static ConfigurableApplicationContext run(Class<?>[] primarySources, | 
实例化一个 SpringApplication 对象
| 1 | public SpringApplication(Class<?>... primarySources) { | 
| 1 | public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) { | 
应用类型
看下 deduceWebApplicationType() 方法:
| 1 | private WebApplicationType deduceWebApplicationType() { | 
web 应用的类型有三个:
- REACTIVE - 当类路径包含 REACTIVE_WEB_ENVIRONMENT_CLASS 且不包含 MVC_WEB_ENVIRONMENT_CLASS 和 JERSEY_WEB_ENVIRONMENT_CLASS 相关的类时返回 
- NONE - 当类路径不存在 WEB_ENVIRONMENT_CLASSES 相关的类时返回 
- SERVLET - 当类路径存在 WEB_ENVIRONMENT_CLASSES 相关的类时返回 
设置初始化器和监听器
| 1 | //设置初始化器 | 
| 1 | private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) { | 
getSpringFactoriesInstances(type) 方法一层层调用,目的是从 “META-INF/spring.factories”文件读取 key 为 type 的 value 名称集合,然后创建对象,返回对象集合。这里从文件中获取的是如下部分:
| 1 | # Application Context Initializers | 
然后调用 setInitializers 和 setListeners 方法设置 SpringApplication 的 变量 initializers 和 listeners
| 1 | private List<ApplicationContextInitializer<?>> initializers; | 
springApplication.run()
该方法创建并刷新一个新的 ApplicationContext,代码如下:
| 1 | public ConfigurableApplicationContext run(String... args) { | 
我们依次来看下上面比较重要的几个地方:
获取 SpringApplicationRunListeners
| 1 | SpringApplicationRunListeners listeners = getRunListeners(args); | 
| 1 | private SpringApplicationRunListeners getRunListeners(String[] args) { | 
首先 getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args) 方法从 spring.factories 文件中找到 key 为 SpringApplicationRunListener 的 value集合,这里只有 EventPublishingRunListener 一个。然后实例化 EventPublishingRunListener 对象:
| 1 | public EventPublishingRunListener(SpringApplication application, String[] args) { | 
然后据此实例化一个 SpringApplicationRunListeners 对象:
| 1 | private final Log log; | 
listeners.starting()
SpringApplicationRunListeners 的 starting 方法如下:
| 1 | public void starting() { | 
我们再看 EventPublishingRunListener 的 starting 方法:
| 1 | public void starting() { | 
这个我们后面详细说,先知道这里广播一个 ApplicationStartingEvent 事件出去,让监听了该事件的监听器能够做相应的处理。后面的 environmentPrepared 方法、started 方法、running 方法也是类似。
创建 ConfigurableEnvironment 对象并配置
| 1 | private ConfigurableEnvironment prepareEnvironment( | 
| 1 | private ConfigurableEnvironment getOrCreateEnvironment() { | 
| 1 | protected void configureEnvironment(ConfigurableEnvironment environment, | 
创建上下文 ApplicationContext
| 1 | protected ConfigurableApplicationContext createApplicationContext() { | 
相关常量定义如下:
| 1 | /** | 
准备上下文
| 1 | private void prepareContext(ConfigurableApplicationContext context, | 
刷新上下文
| 1 | private void refreshContext(ConfigurableApplicationContext context) { | 
| 1 | protected void refresh(ApplicationContext applicationContext) { | 
AbstractApplicationContext 的 refresh 方法我们就不看了,前面介绍 SpringIOC 容器的时候看过了。。。
初始化器 ApplicationContextInitializer
在实例化 SpringApplication 对象的时候设置了相关的初始化器和监听器。这一部分我们先看下几个初始化器。
具体有从 spring-boot 的 META-INF/spring.factories 文件中获取到的四个:
| 1 | # Application Context Initializers | 
从 spring-boot-autoconfigure 的 META-INF/spring.factories 文件中获取到的两个:
| 1 | # Initializers | 
然后会在 SpringApplication 调用 prepareContext() 方法中 applyInitializers(context) 的时候,依次执行各个初始化器的 initialize(context) 方法。
| 1 | protected void applyInitializers(ConfigurableApplicationContext context) { | 
ConfigurationWarningsApplicationContextInitializer
其 initialize(context) 方法代码如下:
| 1 | public void initialize(ConfigurableApplicationContext context) { | 
在实例化 ConfigurationWarningsPostProcessor 时首先会调用 getChecks 获得 Check[],传入到 ConfigurationWarningsPostProcessor 的构造器中.代码如下:
| 1 | protected Check[] getChecks() { | 
其返回了一个 ComponentScanPackageCheck. 其代码如下:
| 1 | protected static class ComponentScanPackageCheck implements Check { | 
将 org.springframework , org 加入到了PROBLEM_PACKAGES 中.
ConfigurationWarningsPostProcessor 构造器如下:
| 1 | public ConfigurationWarningsPostProcessor(Check[] checks) { | 
这样 ConfigurationWarningsPostProcessor 就持有了 ComponentScanPackageCheck。然后将 ConfigurationWarningsPostProcessor 添加到 context 的 beanFactoryPostProcessors变量当中。
| 1 | /** BeanFactoryPostProcessors to apply on refresh */ | 
ContextIdApplicationContextInitializer
其 initialize(context) 方法代码如下:
| 1 | public void initialize(ConfigurableApplicationContext applicationContext) { | 
这里主要是给 context 设置唯一 id,如果有父上下文,则根据父上下文的 ContextId 生成一个新的 ContextId,否则创建一个新的ContextId:从 environment 中读取 “spring.application.name” 变量的值,没有则设置 id 为 application。
DelegatingApplicationContextInitializer
其 initialize(context) 方法代码如下:
| 1 | private static final String PROPERTY_NAME = "context.initializer.classes"; | 
该初始化器的作用是:读取配置的 “context.initializer.classes” 值,也就是我们自定义的初始化类(实现ApplicationContextInitializer),然后实例化后依次调用其 initialize(context) 方法。
ServerPortInfoApplicationContextInitializer
其 initialize(context) 方法代码如下:
| 1 | public class ServerPortInfoApplicationContextInitializer | 
将其添加的 context 的监听器集合中,监听到 WebServerInitializedEvent 事件时执行 onApplicationEvent() 方法
SharedMetadataReaderFactoryContextInitializer
其 initialize(context) 方法代码如下:
| 1 | public void initialize(ConfigurableApplicationContext applicationContext) { | 
将 CachingMetadataReaderFactoryPostProcessor 添加到 context 的 beanFactoryPostProcessors变量当中。
ConditionEvaluationReportLoggingListener
其 initialize(context) 方法代码如下:
| 1 | public void initialize(ConfigurableApplicationContext applicationContext) { | 
将其添加的 context 的监听器集合中。
自定义初始化器
- 使用spring.factories方式: - 首先我们自定义个类实现了ApplicationContextInitializer,然后在resource下面新建/META-INF/spring.factories文件。 - 1 
 2- org.springframework.context.ApplicationContextInitializer=\ 
 org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,\
- application.yml 添加配置方式: - 1 
 2- org.springframework.context.ApplicationContextInitializer=\ 
 org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,\
- 启动类直接添加方式: - 1 
 2
 3- application.addInitializers((ApplicationContextInitializer<ConfigurableApplicationContext>) applicationContext -> { 
 System.out.println("======MyApplicationContextInitializer======");
 });
监听器 ApplicationListener
在实例化 SpringApplication 对象的时候设置了相关的初始化器和监听器。这一部分我们看下几个监听器。
具体有从 spring-boot 的 META-INF/spring.factories 文件中获取到的九个:
| 1 | # Application Listeners | 
从 spring-boot-autoconfigure 的 META-INF/spring.factories 文件中获取到的一个:
| 1 | # Application Listeners | 
SpringApplicationRunListeners
我们先来看下 SpringApplicationRunListeners,该对象是 SpringApplication.run() 方法执行一开始的时候创建的:
| 1 | SpringApplicationRunListeners listeners = getRunListeners(args); | 
| 1 | private SpringApplicationRunListeners getRunListeners(String[] args) { | 
SpringApplicationRunListeners 内部持有 SpringApplicationRunListener 集合(也是从 spring.factories 文件中获取,只有一个 EventPublishingRunListener 对象)和1个 Log 日志类。用于SpringApplicationRunListener 监听器的批量执行。
| 1 | private final Log log; | 
SpringApplicationRunListener 看名字也知道用于监听 SpringApplication 的 run 方法的执行。run 方法中有几个步骤会出发对应的事件监听器:
- starting - run方法执行后立即执行,对应事件 ApplicationStartingEvent 
- environmentPrepared - 上下文 ApplicationContext 创建之前并且环境信息 ConfigurableEnvironment 准备好的时候调用;对应事件的类型是 ApplicationEnvironmentPreparedEvent 
- contextPrepared - 上下文 ApplicationContext 创建之后并设置了环境并调用了各个初始化器的 initialize 方法之后调用;没有对应事件 
- contextLoaded - 上下文 ApplicationContext 创建并加载之后并在refresh之前调用;对应事件的类型是ApplicationPreparedEvent 
- started - 上下文 ApplicationContext 刷新之后调用;对应事件的类型是 ApplicationStartedEvent 
- running - run 方法结束之前调用;对应事件的类型是 ApplicationReadyEvent 
- failure - run 方法捕获异常的时候调用;对应事件的类型是 ApplicationFailedEvent 
SpringApplicationRunListener
SpringApplicationRunListener 接口只有一个实现类 EventPublishingRunListener,其构造方法如下:
| 1 | public EventPublishingRunListener(SpringApplication application, String[] args) { | 
在实例化 EventPublishingRunListener 对象的时候,创建一个事件广播器 SimpleApplicationEventMulticaster,
并将所有的事件监听器保存起来:
| 1 | public void addApplicationListener(ApplicationListener<?> listener) { | 
我们以 listeners.starting() 为例, 会调用 EventPublishingRunListener 对象的 starting 方法:
| 1 | public void starting() { | 
这里创建一个 ApplicationStartingEvent 对象作为调用事件广播器的 multicastEvent() 方法的参数,multicastEvent() 方法相关代码如下:
| 1 | public void multicastEvent(ApplicationEvent event) { | 
我们先看下 getApplicationListeners 方法怎么根据事件类型获取匹配的事件监听器的:
| 1 | protected Collection<ApplicationListener<?>> getApplicationListeners( | 
缓存部分我们不看,主要看 retrieveApplicationListeners 方法就行,代码如下:
| 1 | private Collection<ApplicationListener<?>> retrieveApplicationListeners( | 
一个监听器支不支持该事件我们看 supportsEvent 方法:
| 1 | protected boolean supportsEvent( | 
这里可以看出 listener 不是 GenericApplicationListener 的话,则创建一个适配器对象GenericApplicationListenerAdapter。然后调用 smartListener.supportsEventType() 检查事件类型和事件源类型。如果是我们自定义的事件,则调用的是 GenericApplicationListenerAdapter 对象的 supportsEventType() 方法。代码如下:
| 1 | public boolean supportsEventType(ResolvableType eventType) { | 
这里判断事件监听器是不是 SmartApplicationListener 的实现类:
- 是则调用他们自己的 supportsEventType 方法。SmartApplicationListener 的实现类有三个:ConfigFileApplicationListener、GenericApplicationListenerAdapter、SourceFilteringListener。这里我们以 ConfigFileApplicationListener 为例,其 supportsEventType 方法如下: - 1 
 2
 3
 4- public boolean supportsEventType(Class<? extends ApplicationEvent> eventType) { 
 return ApplicationEnvironmentPreparedEvent.class.isAssignableFrom(eventType)
 || ApplicationPreparedEvent.class.isAssignableFrom(eventType);
 }- 很明显可以看出 ConfigFileApplicationListener 只支持 ApplicationEnvironmentPreparedEvent 和 ApplicationPreparedEvent。 
- 不是则用监听器实现 ApplicationListener 接口时传递的泛型类型和该事件类型比较。 
ConfigFileApplicationListener
ConfigFileApplicationListener 对事件的监听代码如下:
| 1 | public void onApplicationEvent(ApplicationEvent event) { | 
监听两个事件:ApplicationEnvironmentPreparedEvent 和 ApplicationPreparedEvent。
加载配置文件
监听到 ApplicationEnvironmentPreparedEvent 时的处理代码如下:
| 1 | private void onApplicationEnvironmentPreparedEvent( | 
这里我们主要看 ConfigFileApplicationListener 自身的 postProcessEnvironment 方法:
| 1 | public void postProcessEnvironment(ConfigurableEnvironment environment, | 
| 1 | protected void addPropertySources(ConfigurableEnvironment environment, | 
这里创建了一个 Loader 对象并调用 load() 方法。
Loader 是 ConfigFileApplicationListener 的一个内部类,其作用是加载候选属性源并配置活动配置文件。其相关代码如下:
| 1 | Loader(ConfigurableEnvironment environment, ResourceLoader resourceLoader) { | 
加载配置文件信息的代码在 load() 方法里:
| 1 | private void load(Profile profile, DocumentFilterFactory filterFactory, | 
getSearchLocations() 方法默认返回:classpath:/,classpath:/config/,file:./,file:./config/
getSearchNames() 方法默认返回:application
| 1 | private void load(String location, String name, Profile profile, | 
监听 ApplicationPreparedEvent
ApplicationPreparedEvent 发生在准备好上下文但是刷新之前。
ConfigFileApplicationListener 监听到该事件的时候做了什么呢?
| 1 | private void onApplicationPreparedEvent(ApplicationEvent event) { | 
从代码可以看出来只做了一件事情:添加了一个叫 PropertySourceOrderingPostProcessor 的 BeanFactoryPostProcessor。
BeanFactoryPostProcessor 在刷新上下文的 invokeBeanFactoryPostProcessors(beanFactory) 时候会实例化并调用。
自定义监听器
| 1 | public class MyApplicationStartedEventListener implements ApplicationListener<ApplicationStartedEvent> { | 
创建一个监听器类实现 ApplicationListener 并写明感兴趣的事件,然后在启动类中添加到 SpringApplication
| 1 | SpringApplication application = new SpringApplication(DemoApplication.class); | 
总结
这一部分介绍了启动流程 springApplication.run() 中做了哪些事情,以及其中涉及到的一些初始化器和事件监听器等。。。