启动流程
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
2org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,\application.yml 添加配置方式:
1
2org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,\启动类直接添加方式:
1
2
3application.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
4public 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() 中做了哪些事情,以及其中涉及到的一些初始化器和事件监听器等。。。