【SpringBoot】SpringBoot 生命周期及相关事件浅析 二
前言
上一章节介绍了 ApplicationStartingEvent ApplicationEnvironmentPreparedEvent 的 生命周期 动作,以及对应 监听器 的行为,本章节继续介绍剩余 事件 相关
版本
SpringBoot 2.3.x
ApplicationContextInitializedEvent
----------------- prepareContext -----------------
private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
// setEnvironment
context.setEnvironment(environment);
// 设置 beanNameGenerator conversionService 等属性
postProcessApplicationContext(context);
// 执行所有 ApplicationContextInitializer
applyInitializers(context);
// 发布事件 ApplicationContextInitializedEvent
listeners.contextPrepared(context);
// ...
}
------------ EventPublishingRunListener ------------
public void contextPrepared(ConfigurableApplicationContext context) {
this.initialMulticaster
.multicastEvent(new ApplicationContextInitializedEvent(this.application, this.args, context));
}
- 设置
environment
属性 - 容器 的后处理,包括注册 BeanNameGenerator 单例,设置
resourceLoader
属性、设置conversionService
属性 - 依次执行所有
ApplicationContextInitializer#initialize
方法,ApplicationContextInitializer 即构造方法中 自动装配 的initializers
属性,共有7
个 - 1)DelegatingApplicationContextInitializer:收集所有
environment
中context.initializer.classes
属性配置的自定义 ApplicationContextInitializer,并执行initialize
方法,换句话说自定义的 ApplicationContextInitializer 优先级最高 - 2)SharedMetadataReaderFactoryContextInitializer:注册 CachingMetadataReaderFactoryPostProcessor 后处理器
- 3)ContextIdApplicationContextInitializer:生成一个 ContextId 类型的 容器标识,并将其注册为 单例
- 4)ConfigurationWarningsApplicationContextInitializer:注册一个 ConfigurationWarningsPostProcessor 后处理器
- 5)RSocketPortInfoApplicationContextInitializer:设置
local.rsocket.server.port
属性 - 6)ServerPortInfoApplicationContextInitializer:设置
local.server.port
等属性 - 7)ConditionEvaluationReportLoggingListener:设置 ConditionEvaluationReport 属性并注册为 单例
- 发布 ApplicationContextInitializedEvent
ApplicationContextInitializedEvent 对应的监听器
- BackgroundPreinitializer:针对 ApplicationContextInitializedEvent 无动作
- DelegatingApplicationListener:同时发布该事件给所有 自定义监听器
ApplicationPreparedEvent
----------------- prepareContext -----------------
private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
// ...
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
/**
* 注册对应单例,比如 springApplicationArguments springBootBanner
*/
beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
if (printedBanner != null) {
beanFactory.registerSingleton("springBootBanner", printedBanner);
}
if (beanFactory instanceof DefaultListableBeanFactory) {
((DefaultListableBeanFactory) beanFactory)
.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
if (this.lazyInitialization) {
context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
}
/**
* 加载所有资源类
*/
Set<Object> sources = getAllSources();
Assert.notEmpty(sources, "Sources must not be empty");
load(context, sources.toArray(new Object[0]));
/**
* 发布事件 ApplicationPreparedEvent
*/
listeners.contextLoaded(context);
}
------------ EventPublishingRunListener ------------
public void contextLoaded(ConfigurableApplicationContext context) {
for (ApplicationListener<?> listener : this.application.getListeners()) {
if (listener instanceof ApplicationContextAware) {
((ApplicationContextAware) listener).setApplicationContext(context);
}
context.addApplicationListener(listener);
}
this.initialMulticaster.multicastEvent(new ApplicationPreparedEvent(this.application, this.args, context));
}
- 注册 ApplicationArguments、Banner 对应的 单例
- 设置
allowBeanDefinitionOverriding
属性,由spring.main
属性控制 - 注册一个 LazyInitializationBeanFactoryPostProcessor 后处理器
- 加载 资源类,基于 BeanDefinitionLoader 的成员属性
AnnotatedBeanDefinitionReader annotatedReader
加载主类,通常情况下我们的主类作为配置类,后续被ConfigurationClassPostProcessor
解析 - 发布 ApplicationPreparedEvent
- 把 SpringApplication 设置的 监听器 与 容器 绑定起来,同时将 SpringApplication 的 监听器 注册到 容器 中,也就是说这部分监听器也可以监听到 容器 的相关事件
ApplicationPreparedEvent 对应的监听器
- CloudFoundryVcapEnvironmentPostProcessor:略
- ConfigFileApplicationListener:注册一个 PropertySourceOrderingPostProcessor 后处理器
- LoggingApplicationListener:注册几个日志相关的 单例
- BackgroundPreinitializer:针对 ApplicationPreparedEvent 无动作
- DelegatingApplicationListener:同时发布该事件给所有 自定义监听器
ApplicationStartedEvent
// 调用容器的 refresh 方法
refreshContext(context);
// 空实现,供拓展
afterRefresh(context, applicationArguments);
stopWatch.stop();
// 打印日志
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
}
/**
* 此处发布 ApplicationStartedEvent
*/
listeners.started(context);
------------ EventPublishingRunListener ------------
public void started(ConfigurableApplicationContext context) {
context.publishEvent(new ApplicationStartedEvent(this.application, this.args, context));
AvailabilityChangeEvent.publish(context, LivenessState.CORRECT);
}
- 在发布 ApplicationStartedEvent 前,有一个很重要的动作
refreshContext
,此处调用了 容器 的refresh
方法,这是 容器 最核心的方法,配置(刷新) 整个 Spring 容器,单例bean
的注册就是发生在此处 - 发布 ApplicationStartedEvent 后,容器还会发布了一个 AvailabilityChangeEvent 事件,标识应用状态为
LivenessState.CORRECT
ApplicationStartedEvent 对应的监听器
- BackgroundPreinitializer:针对 ApplicationStartedEvent 无动作
- DelegatingApplicationListener:同时发布该事件给所有 自定义监听器
ApplicationReadyEvent
/**
* 此处发布 ApplicationReadyEvent
*/
listeners.running(context);
------------ EventPublishingRunListener ------------
public void running(ConfigurableApplicationContext context) {
context.publishEvent(new ApplicationReadyEvent(this.application, this.args, context));
AvailabilityChangeEvent.publish(context, ReadinessState.ACCEPTING_TRAFFIC);
}
- 执行完所有
CommandLineRunner
和ApplicationRunner
后,发布事件ApplicationReadyEvent
- 同时容器发布状态为
ReadinessState.ACCEPTING_TRAFFIC
的AvailabilityChangeEvent
事件,表示应用可以正常通信了
ApplicationReadyEvent 对应的监听器
-
BackgroundPreinitializer:在发布 ApplicationEnvironmentPreparedEvent 事件时,此监听器在后台启动一个线程执行 预热 操作,其用到一个 CountDownLatch 使得在 预热 操作执行完成前,所有线程会阻塞在此处。则 ApplicationReadyEvent 事件到达时,如果 预热 完成,预热线程中断
-
DelegatingApplicationListener:同时发布该事件给所有 自定义监听器
ApplicationFailedEvent
应用启动失败,则发布 ApplicationFailedEvent,细节略
总结
SpringBoot
抽象出SpringApplication:Spring应用
的概念,它会根据上下文创建对应的Environment
ApplicationContext
Environment
ApplicationContext
等都是Spring
的核心组件,SpringBoot
将其整合到一块,即我们所谓的约定大于配置
ApplicationContext
有它自己的生命周期,在容器的启动过程中,也会发布对应的事件SpringApplication
也有它自己的生命周期,即我们本文介绍的重点监听器
于事件
类似于BeanPostProcessor
于Bean
,前者允许我们在合适的时机对SpringApplication
进行拓展,比如SpringCloud
的整合,后者允许我们在合适的时机对容器中的Bean
进行拓展,比如属性的注入
- 事件驱动是
SpringBoot
的核心,还是有必要掌握的