倚楼听风雨
淡看江湖路

关于 SpringBoot 事件的生命周期大全讲解

上一次简单的分享了一下 Spring Boot 的源码导入教程,那么源码导入成功了,最重要的自然就是要阅读源码,今天简单的浅析一下在 Spring Boot 的整个生命周期当中,扮演重要角色的 SpringApplicationRunListener,换句话说,了解了 Spring Boot 的事件机制,也就全面的了解 SpringApplication.run 的生命周期。

注意:本文的源码分析均在 Spring Boot 2.7.x 分支下进行。

事件机制在 Spring Boot 中的运转机制

Spring Boot 的事件机制或者说 Spring 的 Event 事件模型都是基于观察者设计模式而实现,关于观察者设计模式的浅析可以参考文末「相关文章阅读」了解。

无论看啥,我们基本都要从 Spring Boot 的 main 运行方法看起,我们都知道 Spring Boot 运行下面这行代码来启动。

我们点进去源码,看到 run 方法实际的执行如下:

我们可以看到,在实际的 run 方法中,先是调用了 SpringApplication 构造,然后在执行 run 方法,SpringApplication 构造注释如下:

我们可以看到,SpringApplication 构造中通过 setListeners 将 ApplicationListener 进行初始化,与 ApplicationContextInitializer 相同,都是通过 SpringFactoriesLoader 获取 META-INF/spring.factories 中的对应配置,然后进行初始化(实例化),然后将结果集合添加到 SpringApplication 成员变量 org.springframework.boot.SpringApplication#listeners 中。说人话就是将 Spring Boot 系统定义的所有监听器(spring.factories 中配置的)都加载进来进行实例化,到时候实现事件监听。

关于 SpringBoot 事件的生命周期大全讲解的图片-高老四博客 第1张

关于 SpringBoot 事件的生命周期大全讲解的图片-高老四博客 第2张

再来看一下 run 方法的源码注释:

在这个 run 方法中,我们可以看到,一开始,也是通过读取 spring.factories 配置文件的方式,实例化 SpringApplicationRunListener,并且将结果集合放在了 org.springframework.boot.SpringApplicationRunListeners#listeners 当中。这个 SpringApplicationRunListener 监听接口可以理解为 SpringBoot 生命周期事件机制的核心接口了,里面按照 Spring Boot 整个生命周期定义了一系列的方法,通过实现这些方法在启动各个流程的时候就可以加入指定的业务逻辑处理。

来个鱼骨头简单地感受一下

关于 SpringBoot 事件的生命周期大全讲解的图片-高老四博客 第3张

SpringApplicationRunListener 在 Spring Boot 中有一个默认的实现类 EventPublishingRunListener,它也就是 spring.factories 文件中配置的要实例化的类。

关于 SpringBoot 事件的生命周期大全讲解的图片-高老四博客 第4张

也就是说在默认情况下,Spring Boot 在初始化时触发的事件都是 EventPublishingRunListener 来实现的,在 EventPublishingRunListener 类中的构造方法,我们可以看到熟悉的 SpringApplication、args 以及一个事件广播器SimpleApplicationEventMulticaster,就是通过这个事件广播器将事件传递给所有的监听器。

更多细节内容可以自己捋一遍源码,走一下这个过程。

Spring Boot 中默认的事件机制

上面简单的介绍了一下 Spring Boot 的事件机制基本原理,这里再来具体说一下在 Spring Boot 在启动的整个生命周期中都有哪些核心事件以及事件对应的监听都干了些什么,更好帮助我们了解 Spring Boot 都做了什么内容。

其实对应上面提到的 SpringApplicationRunListener 的七个声明的方法,自然对应的也就有七个对应的事件,Spring Boot 中所有的事件 Event 都继承自 SpringApplicationEvent,SpringApplicationEvent 继承自 Spring 的 ApplicationEvent,保证事件与 SpringApplication 的关联。

关于 SpringBoot 事件的生命周期大全讲解的图片-高老四博客 第5张

ApplicationStartingEvent

应用开始启动中事件,默认情况下,Spring Boot 中有三个监听器监听该事件。

LoggingApplicationListener

这个监听玩转的是 Spring Boot 的日志系统,在 LoggingApplicationListener 未启动之前,默认使用 LogBack 日志体系,这个监听实在启动中从系统中查找 LoggingSystem,并且进行初始化。源码可看 org.springframework.boot.context.logging.LoggingApplicationListener#onApplicationStartingEvent。

BackgroundPreinitializer

此监听在该事件中不生效,详解见下方。

DelegatingApplicationListener

实际上,在应用启动中这个阶段,这个监听没干啥,在 org.springframework.boot.context.config.DelegatingApplicationListener#onApplicationEvent 中判断了当前事件是否是「ApplicationEnvironmentPreparedEvent」才真正生效。

关于 SpringBoot 事件的生命周期大全讲解的图片-高老四博客 第6张

ApplicationEnvironmentPreparedEvent

环境准备完成事件,默认情况下,Spring Boot 中有六个监听器监听该事件。

EnvironmentPostProcessorApplicationListener

就是加载配置文件,application.yml、application.properties。

AnsiOutputApplicationListener

让日志文件或者是控制台支持彩色输出,是日志可读性提高。

LoggingApplicationListener

上面是 LoggingSystem 初始化,这次是调用 org.springframework.boot.context.logging.LoggingApplicationListener#initialize 进行日志初始化操作,包括参数设置、日志文件、日志级别等。

BackgroundPreinitializer

Spring Boot 对于一些比较耗时的任务会使用一个后台线程提前触发它们开始进行初始化操作,即「预初始化」,在源码中 org.springframework.boot.autoconfigure.BackgroundPreinitializer#performPreinitialization 我们可以看到,预初始化包含了 ConversionServiceInitializer(转换器、格式化)、ValidationInitializer(校验)、MessageConverterInitializer(HTTP 请求和响应)、JacksonInitializer(Jackson 配置)、CharsetInitializer(字符集 )。

DelegatingApplicationListener

在上面提到,这个监听在此次事件中才正式生效,主要作用是读取配置文件中的「context.listener.classes」属性,也就是说通过这个监听初始化配置该属性的监听器,然后把「ApplicationStartedEvent」这个事件广播给他们,从而实现一些其他业务逻辑处理。

FileEncodingApplicationListener

检测编码。

关于 SpringBoot 事件的生命周期大全讲解的图片-高老四博客 第7张

ApplicationContextInitializedEvent

该事件下默认的监听都没干什么,但是你要了解前面的 run 方法生命周期过程中,这里都做了些什么。

BackgroundPreinitializer

没干啥。

DelegatingApplicationListener

没干啥。

关于 SpringBoot 事件的生命周期大全讲解的图片-高老四博客 第8张

ApplicationPreparedEvent

上下文已经实例化好事件。

EnvironmentPostProcessorApplicationListener

执行 org.springframework.boot.env.EnvironmentPostProcessorApplicationListener#finish 环境加载完成业务。

LoggingApplicationListener

本次是将 LoggingSystem 注册到 Bean 工厂当中。

BackgroundPreinitializer

啥也没干。

DelegatingApplicationListener

啥也没干。

关于 SpringBoot 事件的生命周期大全讲解的图片-高老四博客 第9张

ApplicationStartedEvent

应用成功启动事件,当然 BackgroundPreinitializer、DelegatingApplicationListener 两个监听也没什么动作,该周期最重要的事情其实是启动 Spring 容器,实例化单例 Bean。

关于 SpringBoot 事件的生命周期大全讲解的图片-高老四博客 第10张

ApplicationReadyEvent

应用已准备好事件。

SpringApplicationAdminMXBeanRegistrar

Spring Boot 有一个远程管理 Spring Boot 的功能,SpringApplicationAdminMXBean 就是 JMX 中的 MBean,也就是 Jconsole 中看到的那个,而这个监听器就是负责将 ready 属性从 false 变为 true,通知 Spring Boot 已经启动好了。

BackgroundPreinitializer

在此监听中,对于 ApplicationReadyEvent 事件有一个 CountDownLatch 的 await 阻塞,我们都知道在 CountDownLatch 中 await 可以让主线程阻塞等待,然后 countDown 减到 0 的时候,主线程执行,这里的目的就是在应用已经准备好之后,让预热也执行完毕,虽然预初始化的东西耗时,咱们让他提前启动,但是应用最终启动好了,预热的东西也得启动好,所以这里会进行一下阻塞,让计数器为 0 在执行后续的主线程操作。

DelegatingApplicationListener

啥也没干。

关于 SpringBoot 事件的生命周期大全讲解的图片-高老四博客 第11张

ApplicationFailedEvent

EnvironmentPostProcessorApplicationListener

调用 org.springframework.boot.env.EnvironmentPostProcessorApplicationListener#finish 将系统日志归档。

LoggingApplicationListener

org.springframework.boot.context.logging.LoggingApplicationListener#cleanupLoggingSystem,执行日志清理工作

BackgroundPreinitializer

同「ApplicationReadyEvent」事件,都是执行 preinitializationComplete.await();

DelegatingApplicationListener

啥也没干。

ConditionEvaluationReportLoggingListener

输出错误日志。

关于 SpringBoot 事件的生命周期大全讲解的图片-高老四博客 第12张

好了,经过上面的分析,其实我们发现有一个问题,就是在整个事件的生命周期中,有很多「啥也没干」的事件监听也参与了事件触发,老四个人觉得算是多带来了一些无效的处理而带来系统消耗。

相关文章阅读

  1. IntelliJ IDEA 导入 Spring Boot 源码教程
  2. 浅析设计模式第十四章之观察者模式
  3. 浅析Java反射系列相关基础知识(上)之类的加载以及反射的基本应用
  4. 阿里巴巴Java开发手册第六章-二方库依赖篇

更博不易,如果觉得文章对你有帮助并且有能力的老铁烦请捐赠盒烟钱,点我去赞助。或者扫描文章下面的微信/支付宝二维码打赏任意金额(点击「给你买杜蕾斯」),也可以加入本站封闭式交流论坛「DownHub」开启新世界的大门,老四这里抱拳谢谢诸位了。捐赠时请备注姓名或者昵称,因为您的署名会出现在赞赏列表页面,您的捐赠钱财也会被用于小站的服务器运维上面,再次抱拳感谢。

赞(7) 给你买杜蕾斯
本站原创文章受自媒体平台原创保护,未经允许不得转载高老四博客 » 关于 SpringBoot 事件的生命周期大全讲解

开始你的表演 抢沙发

觉得文章有用就打赏一下老四,鼓励我更好的创作

非常感谢你的打赏,我们将继续给力更多优质内容,让我们一起创建更加美好的网络世界!

支付宝扫一扫打赏

微信扫一扫打赏

登录

找回密码

注册