【SpringBoot】SpringBoot 生命周期及相关事件浅析 一
前言
阅读本系列章节前,建议复习一下 Spring事件、事件监听器、事件发布 相关
【源码】Spring —— ApplicationEvent ApplicationListener ApplicationEventMulticaster
SpringBoot 提供了事件父类 SpringApplicationEvent,继承自 ApplicationEvent
其下定义了 7
个事件,本系列结合部分源码解读 SpringBoot 何时发布这些 事件?对应的 事件监听器 都做了什么?
版本
SpringBoot 2.3.x
SpringApplication
SpringApplication,Spring 应用的抽象。在 SpringBoot 中,我们可以通过一个简单的 main
方法,来启动一个 Spring 应用
SpringApplication 启动
public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
return run(new Class[]{primarySource}, args);
}
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
return (new SpringApplication(primarySources)).run(args);
}
即创建一个 SpringApplication 实例,调用 run
方法
SpringApplication 实例构造
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
// ResourceLoader
this.resourceLoader = resourceLoader;
// 资源类
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
// 依据 classpath 推断容器类型
this.webApplicationType = WebApplicationType.deduceFromClasspath();
// 从 spring.factories 加载所有 BootstrapRegistryInitializer
this.bootstrapRegistryInitializers = getBootstrapRegistryInitializersFromSpringFactories();
// 从 spring.factories 加载所有 ApplicationContextInitializer
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
// 从 spring.factories 加载所有 ApplicationListener
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
// 推断主类
this.mainApplicationClass = deduceMainApplicationClass();
}
属性的初始化,其中 initializers
和 listeners
从 spring.factories
文件读取加载
SpringApplication.run
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
/**
* 创建 DefaultBootstrapContext
* 会基于 bootstrapRegistryInitializers 初始化
*/
DefaultBootstrapContext bootstrapContext = createBootstrapContext();
ConfigurableApplicationContext context = null;
// 属性 java.awt.headless 处理
configureHeadlessProperty();
/**
* 构造 SpringApplicationRunListeners:
* 主要是就是用来发布各种 SpringApplicationEvent
*/
SpringApplicationRunListeners listeners = getRunListeners(args);
// 发布 ApplicationStartingEvent
listeners.starting(bootstrapContext, this.mainApplicationClass);
try {
// 基于 args 构造 ApplicationArguments,即参数行命令
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
/**
* 构造对应的 ConfigurableEnvironment 返回:
* 其中发布了核心事件 ApplicationEnvironmentPreparedEvent
* 对应监听器完成了配置文件的读取解析
*/
ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
// spring.beaninfo.ignore 属性相关
configureIgnoreBeanInfo(environment);
// 打印 banner 并返回 Banner 对象
Banner printedBanner = printBanner(environment);
// 根据 webApplicationType 创建对应的容器
context = createApplicationContext();
context.setApplicationStartup(this.applicationStartup);
/**
* 在执行完所有 ApplicationContextInitializer 后
* 发布事件 ApplicationContextInitializedEvent
* 在加载完所有资源类后发布事件 ApplicationPreparedEvent
*/
prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
/**
* 调用容器的 refresh 方法,单例会在该阶段后期创建
*/
refreshContext(context);
afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
}
/**
* 发布 ApplicationStartedEvent
*/
listeners.started(context);
/**
* 执行所有 CommandLineRunner 和 ApplicationRunner
*/
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
handleRunFailure(context, ex, listeners);
throw new IllegalStateException(ex);
}
try {
/**
* 执行完所有 CommandLineRunner 和 ApplicationRunner 后,
* 发布事件 ApplicationReadyEvent
*/
listeners.running(context);
}
catch (Throwable ex) {
handleRunFailure(context, ex, null);
throw new IllegalStateException(ex);
}
return context;
}
此处先贴出 run
方法的所有代码,做一个小总结:
SpringBoot
是基于事件驱动来管理拓展SpringApplication
的,重要的事件如下:- 1)在创建好
DefaultBootstrapContext
和SpringApplicationRunListeners
后,发布第一个事件ApplicationStartingEvent
- 2)构造
ConfigurableEnvironment
,Environment
是SpringBoot
最核心的模块之一,在该过程中,会发布事件ApplicationEnvironmentPreparedEvent
- 3)创建对应的容器(
ApplicationContext
),执行对应的ApplicationContextInitializer
后,发布事件ApplicationContextInitializedEvent
- 4)加载完对应资源类的
BeanDefinition
后,发布事件ApplicationPreparedEvent
- 5)执行完容器的
refresh
方法后,发布事件ApplicationStartedEvent
- 6)执行所有
CommandLineRunner
和ApplicationRunner
后,发布事件ApplicationReadyEvent
- 7)启动失败时发布事件
ApplicationFailedEvent
- 针对上述事件,就可以提供对应的监听器,在恰当的时机进行功能拓展,比如配置文件的解析等,接下来就针对对应事件的行为及其对应的监听器进行了解
ApplicationStartingEvent
/**
* 加载对应的 SpringApplicationRunListener
* 封装成 SpringApplicationRunListeners
*/
SpringApplicationRunListeners listeners = getRunListeners(args);
/**
* SpringApplicationRunListener#starting,
* 此处发布 ApplicationStartingEvent
*/
listeners.starting();
------------ EventPublishingRunListener ------------
public void starting() {
this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args));
}
- 这里实例化了 SpringApplicationRunListeners,SpringApplicationRunListeners 就是对内部 SpringApplicationRunListener 的一层封装,之后 SpringApplication 生命周期相关的 事件 将由 SpringApplicationRunListeners 来发布,其本质就是循环调用内部所有 SpringApplicationRunListener 对应方法
- SpringApplicationRunListener 就是一个模板接口,定义了 SpringApplication 生命周期要发布 事件 的模板,SpringBoot 提供了一个实现类 EventPublishingRunListener,在上述代码的
getRunListeners
方法中,自动装配并创建 EventPublishingRunListener 的示例返回 - EventPublishingRunListener 发布 事件 是委托给内部的 SimpleApplicationEventMulticaster 来实现的,即就是将 事件 发布给对应 事件监听器
- 这里发布了 ApplicationStartingEvent 事件
ApplicationStartingEvent 对应的监听器
监听 ApplicationStartingEvent 的监听器有
- LoggingApplicationListener:日志相关
- BackgroundPreinitializer:针对 ApplicationStartingEvent 无动作
- DelegatingApplicationListener:针对 ApplicationStartingEvent 无动作
- LiquibaseServiceLocatorApplicationListener:liquibase 相关
ApplicationEnvironmentPreparedEvent
---------------- prepareEnvironment ----------------
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) {
// 创建对应的 ConfigurableEnvironment
ConfigurableEnvironment environment = getOrCreateEnvironment();
/**
* 设置 convsersionService
* 基于参数行命令来填充 environment
*/
configureEnvironment(environment, applicationArguments.getSourceArgs());
ConfigurationPropertySources.attach(environment);
// ApplicationEnvironmentPreparedEvent
listeners.environmentPrepared(bootstrapContext, environment);
// 将 defaultProperties 移到末尾(优先级最低)
DefaultPropertiesPropertySource.moveToEnd(environment);
// additionalProfiles 属性生效
configureAdditionalProfiles(environment);
/**
* spring.main 相关属性绑定
*/
bindToSpringApplication(environment);
if (!this.isCustomEnvironment) {
environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,
deduceEnvironmentClass());
}
ConfigurationPropertySources.attach(environment);
return environment;
}
------------ EventPublishingRunListener ------------
public void environmentPrepared(ConfigurableEnvironment environment) {
this.initialMulticaster
.multicastEvent(new ApplicationEnvironmentPreparedEvent(this.application, this.args, environment));
}
- 首先创建了 ConfigurableEnvironment 实例
- 初步配置后,发布 ApplicationEnvironmentPreparedEvent 事件,该 事件 相关的 监听器 动作比较大,SpringBoot 强大的配置能力也基于此实现
- 后续动作,比如绑定相关配置到当前 SpringApplication 实例,之后返回配置好的 ConfigurableEnvironment 实例
ApplicationEnvironmentPreparedEvent 对应的监听器
- ConfigFileApplicationListener:在这个 监听器 中,自动装配其他
4
个 EnvironmentPostProcessor(ConfigFileApplicationListener 本身也是一个 EnvironmentPostProcessor),然后依次调用了它们的postProcessEnvironment
方法 - 1)SystemEnvironmentPropertySourceEnvironmentPostProcessor:将
environment
中名为systemEnvironment
的 PropertySource 替换为 OriginAwareSystemEnvironmentPropertySource 类型的(可调用getOrigin
方法获取对应的 SystemEnvironmentOrigin) - 2)SpringApplicationJsonEnvironmentPostProcessor:解析
environment
所有 PropertySource 中的spring.application.json
和SPRING_APPLICATION_JSON
属性 - 3)CloudFoundryVcapEnvironmentPostProcessor:SpringCloud 相关
- 4)ConfigFileApplicationListener:该监听器本身也是最核心的 EnvironmentPostProcessor:给
environment
添加一个名为random
的 PropertySource;加载environment
的activeProfiles
属性;加载配置文件的所有配置到environment
的propertySources
中 - 5)DebugAgentEnvironmentPostProcessor:Spring Reactor 相关
- AnsiOutputApplicationListener:解析
spring.output.ansi.enabled
属性 - LoggingApplicationListener:日志相关
- ClasspathLoggingApplicationListener:日志输出
classpath
信息 - BackgroundPreinitializer:启动一个线程异步执行 实例化DefaultFormattingConversionService、实例化AllEncompassingFormHttpMessageConverter 等动作,该行为可以通过
spring.backgroundpreinitializer.ignore
属性控制 - DelegatingApplicationListener:解析
context.listener.classes
属性对应的所有自定义的 事件监听器,在这之后的事件也会同样发布给这些 监听器。换句话说,用户可以 自定义监听器 监听 ApplicationEnvironmentPreparedEvent 及其之后的所有 ApplicationEvent 事件(注意,监听不到 ApplicationStartingEvent) - FileEncodingApplicationListener:如果设置了
spring.mandatory-file-encoding
属性,则当其与系统的file.encoding
属性不同时,输出相关日志信息
总结
本章节介绍了 ApplicationStartingEvent ApplicationEnvironmentPreparedEvent 的 生命周期 动作,以及对应 监听器 的行为,避免篇幅太长,下章节继续
关于配置文件加载到 Environment 相关,在 2.4.x 版本进行了不兼容改动,更多细节可参考下文: