当前位置: 首页 > news >正文

深入解析:Spring Boot 深入剖析:SpringApplicationRunListener

深入解析:Spring Boot 深入剖析:SpringApplicationRunListener

在研究SpringBoot的启动源码的时候我们看到run方法中有一个之前没见过的类SpringApplicationRunListeners 类,那么这个类的主要作用是什么呢?接下来我们来解析一下这个类

public ConfigurableApplicationContext run(String... args) {
、、、、、、
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting(bootstrapContext, this.mainApplicationClass);
、、、、、、
}

SpringApplicationRunListeners 

当我们点开SpringApplicationRunListeners查看其源码的时候我们发现,SpringApplicationRunListeners内部含有一个集合用来存储SpringApplicationRunListener类对象。同时大部分方法的模式都是调用doWithListeners方法,区别在于传递的参数不同。其实这些大部分的方法都是事件发布的方法,而他的那个集合SpringApplicationRunListener对象则是事件监听对象,因此这个类整体的作用我们就有了一个大概的了解--当内部的不同方法被调用的时候则会发布事件给SpringApplicationRunListener对象,而SpringApplicationRunListener对象收到事件后则会做出对应的处理

class SpringApplicationRunListeners {
private final Log log;
private final List listeners;
private final ApplicationStartup applicationStartup;
SpringApplicationRunListeners(Log log, List listeners,
ApplicationStartup applicationStartup) {
this.log = log;
this.listeners = List.copyOf(listeners);
this.applicationStartup = applicationStartup;
}
void starting(ConfigurableBootstrapContext bootstrapContext, Class mainApplicationClass) {
doWithListeners("spring.boot.application.starting", (listener) -> listener.starting(bootstrapContext),
(step) -> {
if (mainApplicationClass != null) {
step.tag("mainApplicationClass", mainApplicationClass.getName());
}
});
}
void environmentPrepared(ConfigurableBootstrapContext bootstrapContext, ConfigurableEnvironment environment) {
doWithListeners("spring.boot.application.environment-prepared",
(listener) -> listener.environmentPrepared(bootstrapContext, environment));
}
void contextPrepared(ConfigurableApplicationContext context) {
doWithListeners("spring.boot.application.context-prepared", (listener) -> listener.contextPrepared(context));
}
void contextLoaded(ConfigurableApplicationContext context) {
doWithListeners("spring.boot.application.context-loaded", (listener) -> listener.contextLoaded(context));
}
、、、、、、
private void doWithListeners(String stepName, Consumer listenerAction) {
doWithListeners(stepName, listenerAction, null);
}
private void doWithListeners(String stepName, Consumer listenerAction,
Consumer stepAction) {
StartupStep step = this.applicationStartup.start(stepName);
this.listeners.forEach(listenerAction);
if (stepAction != null) {
stepAction.accept(step);
}
step.end();
}
}

下面我们挑两个主要方法来进行解析

void environmentPrepared(ConfigurableBootstrapContext bootstrapContext, ConfigurableEnvironment environment) {
doWithListeners("spring.boot.application.environment-prepared",
(listener) -> listener.environmentPrepared(bootstrapContext, environment));
}

可以看到大部分的事件发布方法本质都是调用了doWithListeners,同时传递的第一个参数的事件类型不同标志着不同事件的触发,第二个参数则是使用了函数接口生成一个类对象传递给这个方法。

整个类的关键则是在第二个方法,doWithListeners首先则是采用了StartupStep 统计每个步骤的耗时,然后利用了 Java 8 的函数式编程特性遍历了listeners集合随后调用了函数接口listenerAction的方法,目的就是批量触发所有监听器的某个事件方法。而这个方法我们在将解析上一个方法源码的时候已经看到了是调用的则是SpringApplicationRunListener的内部方法

private void doWithListeners(String stepName, Consumer listenerAction) {
doWithListeners(stepName, listenerAction, null);
}
private void doWithListeners(String stepName, Consumer listenerAction,
Consumer stepAction) {
StartupStep step = this.applicationStartup.start(stepName);
this.listeners.forEach(listenerAction);
if (stepAction != null) {
stepAction.accept(step);
}
step.end();
}

所以本质上SpringApplicationRunListeners的作用则是发布事件,遍历当前类集合中每个SpringApplicationRunListener并且调用其对应这个事件的方法来实现事件的发布。

是 Spring Boot 应用启动过程的“广播站”,专门发布与应用生命周期(如开始启动、环境准备、上下文准备等)紧密相关的固定事件。而相较于ApplicationEventMulticaster 对于SpringApplicationRunListeners来说则更像是一个事件生产者。当我们分析完SpringApplicationRunListener源码便能更加深刻的理解

SpringApplicationRunListener

SpringApplicationRunListener 是一个接口,它定义了用于监听 SpringApplication 的 run() 方法执行过程中各个关键生命周期节点的回调方法。它的实现类通过这些回调方法,在特定的时间点执行必要的逻辑(最主要的就是发布事件)。

为什么说SpringApplicationRunListener 是发布事件呢?我们看看SpringApplicationRunListener 实现类的源码便可知道为啥时发布事件

class EventPublishingRunListener implements SpringApplicationRunListener, Ordered {
private final SpringApplication application;
private final String[] args;
private final SimpleApplicationEventMulticaster initialMulticaster;
EventPublishingRunListener(SpringApplication application, String[] args) {
this.application = application;
this.args = args;
this.initialMulticaster = new SimpleApplicationEventMulticaster();
}
@Override
public int getOrder() {
return 0;
}
@Override
public void starting(ConfigurableBootstrapContext bootstrapContext) {
multicastInitialEvent(new ApplicationStartingEvent(bootstrapContext, this.application, this.args));
}
@Override
public void environmentPrepared(ConfigurableBootstrapContext bootstrapContext,
ConfigurableEnvironment environment) {
multicastInitialEvent(
new ApplicationEnvironmentPreparedEvent(bootstrapContext, this.application, this.args, environment));
}
、、、、、、
private void multicastInitialEvent(ApplicationEvent event) {
refreshApplicationListeners();
this.initialMulticaster.multicastEvent(event);
}
private void refreshApplicationListeners() {
this.application.getListeners().forEach(this.initialMulticaster::addApplicationListener);
}
private static class LoggingErrorHandler implements ErrorHandler {
private static final Log logger = LogFactory.getLog(EventPublishingRunListener.class);
@Override
public void handleError(Throwable throwable) {
logger.warn("Error calling ApplicationEventListener", throwable);
}
}
}

EventPublishingRunListener 是 SpringApplicationRunListener的一个子类实现类,我们可以看到其内部则是有一个SimpleApplicationEventMulticaster 类属性这个属性本质上是ApplicationEventMulticaster类的子类,而ApplicationEventMulticaster类则ApplicationContext内部最为常见的事件广播器主要作用则是监听事件并且广播事件。

当我们我们查看SpringApplicationRunListener不同的方法源码则可以看到不同的方法生成了不同的event事件类型当做参数,最终都是调用的multicastEvent方法,而multicastEvent方法内部的核心则是使用SimpleApplicationEventMulticaster的属性来对当前不同的event事件进行广播处理,最终本质上其实是ApplicationListener类来进行监听并且处理的

特性SpringApplicationRunListenerApplicationListener
关注点Spring Boot 应用的启动生命周期Spring 框架的应用事件(包括Boot启动事件)。
触发时机在 SpringApplication.run() 方法的固定节点被直接调用。任何事件被发布时,由 ApplicationEventMulticaster 通知。
获取方式通过 spring.factories 机制配置。可以是 @Component,或通过 SpringApplication.addListeners() 添加。
作用域仅限于启动过程贯穿整个应用上下文生命周期
主要职责生产/发布启动事件。消费/处理事件(包括启动事件)。

因此我们发现其实SpringApplicationRunListener是一个时间的发布器,通过ApplicationEventMulticaster来对事件进行广播,最终由ApplicationListener监听到不同的事件来进行处理,而SpringApplicationRunListeners我们则可以认为他是一个事件生产器,生产完毕之后调用SpringApplicationRunListener的方法来进行事件广播最终由ApplicationListener来进行事件的处理。

http://www.wxhsa.cn/company.asp?id=5544

相关文章:

  • Hutool 调用第三方接口报错
  • 丑东西经济学:全面分析
  • 深入浅出 Java 多线程:从线程生命周期到并发安全
  • 儿童无屏幕对讲机 Bunny 融资百万美元;腾讯会议推出 AI 托管:先行听会、代听多会、全程记录丨日报
  • Python turtle 海龟画图入门指南
  • uni-app中v-if使用”异常”
  • 如何创建可引导的 macOS Tahoe 安装介质
  • 二叉树遍历
  • Python Socket网络编程(3)
  • 实用指南:有关gitlab14.x版本在内网环境下无法添加webhooks的解决方法
  • 强类型、类型安全
  • 完整教程:数据结构——逻辑结构物理结构
  • 前端面试
  • 外置Tomcat启动Springboot项目后,请求参数中文乱码的问题解决 - yjry
  • gradle项目多模块中主模块加载子模块中的sqlmapper文件方法
  • MCP - 使用 fastmcp 编写 Client 调用 MCP Serverr - Streamable HTTP (四)
  • 全面理解MySQL架构
  • Figma EX 125.7.5 UI原型设计
  • 基于WebSocket的命令与控制工具WSC2详解
  • LocalDateTime节日和平日在时间占比计算方法
  • JSON字符串转换List对象列表 JSONArray toJavaList
  • vue3 使用 docx-preview 预览 Word文档
  • 数据库原理-第三章——SQL
  • 啥是CPU
  • C# Avalonia 15- Animation- CodeAnimation
  • ubuntu 18.04安装mysql 8.0.41
  • Topaz Photo AI Pro 4.0.4 AI图片智能降噪(win版)
  • 阿里云基础设施 AI Tech Day AI 原生,智构未来——AI 原生架构与企业实践专场
  • 实用指南:LINUX910 CENTOS8 新建虚拟机;重设root密码/时间同步
  • 零基础学习PYthon记录