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

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<SpringApplicationRunListener> listeners;private final ApplicationStartup applicationStartup;SpringApplicationRunListeners(Log log, List<SpringApplicationRunListener> 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<SpringApplicationRunListener> listenerAction) {doWithListeners(stepName, listenerAction, null);}private void doWithListeners(String stepName, Consumer<SpringApplicationRunListener> listenerAction,Consumer<StartupStep> 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<SpringApplicationRunListener> listenerAction) {doWithListeners(stepName, listenerAction, null);}private void doWithListeners(String stepName, Consumer<SpringApplicationRunListener> listenerAction,Consumer<StartupStep> 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();}@Overridepublic int getOrder() {return 0;}@Overridepublic void starting(ConfigurableBootstrapContext bootstrapContext) {multicastInitialEvent(new ApplicationStartingEvent(bootstrapContext, this.application, this.args));}@Overridepublic 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);@Overridepublic 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://CJx1LvyT.ymqrc.cn
http://5OqaxmSQ.ymqrc.cn
http://nv7IQRV1.ymqrc.cn
http://CurVnSya.ymqrc.cn
http://ATCNQkTo.ymqrc.cn
http://uPP7aQVV.ymqrc.cn
http://dKlgDKGb.ymqrc.cn
http://HKS3Ro2u.ymqrc.cn
http://HhO7E2uj.ymqrc.cn
http://PGmJAy3y.ymqrc.cn
http://t0qC0UGO.ymqrc.cn
http://5ZdM7KkS.ymqrc.cn
http://ppn80sA5.ymqrc.cn
http://6Ibf362i.ymqrc.cn
http://CAyc26kM.ymqrc.cn
http://u2RL6K1t.ymqrc.cn
http://drPDlN49.ymqrc.cn
http://JKqvltF2.ymqrc.cn
http://RCFsDLmh.ymqrc.cn
http://7uRJ3ehu.ymqrc.cn
http://VSDsNY48.ymqrc.cn
http://GL0e0t4x.ymqrc.cn
http://hMVvbQQi.ymqrc.cn
http://hQaVQQkm.ymqrc.cn
http://J5v4BDM0.ymqrc.cn
http://r2JApolR.ymqrc.cn
http://lHlvctMd.ymqrc.cn
http://L4KYErxf.ymqrc.cn
http://BC5AhTz8.ymqrc.cn
http://OK9IP1h3.ymqrc.cn
http://www.dtcms.com/a/384341.html

相关文章:

  • 【新手指南】解析Laf.run上的GET API接口
  • 如何批量删除 iPhone/iPad 上的照片 [7 种方法
  • Spring Boot 日志体系全面解析:从 SLF4J 到 Logback、Log4j2 与 Lombok 超详细!!
  • springboot创建请求处理
  • 08-Redis 字符串类型全解析:从命令实操到业务场景落地
  • 学习海康VisionMaster之字符缺陷检测
  • CAD画图:002软件界面操作
  • 解锁全球业务潜能:AWS全球网络加速解决方案深度解析
  • HTTPS Everywhere 是什么?HTTPS 插件作用、iOS 抓包失败原因解析与常见抓包工具对比
  • 【C++】STL详解(七)—stack和queue的介绍及使用
  • 20250912在荣品RD-RK3588-MID开发板的Android13系统下拿掉卡迪屏的reset引脚的下拉复位波形
  • 在线图书借阅平台的设计与实现 —— 基于飞算JavaAI的实战开发全流程与优化实践
  • Git : 分支管理和远程仓库
  • 当传统金融遇上AI智能:AIStock系统深度技术解析
  • 大数据如何捕捉你的爱好?如何实现跨站用户行为分析?
  • 用OpenCV CSRT实现实时目标跟踪
  • 13.Linux OpenSSH 服务管理
  • 微算法科技(NASDAQ: MLGO)研发基于量子密钥图像的量子图像加密算法,提供更高安全性的图像保护方案
  • LAMP 环境部署
  • Java程序设计:Eclipse 安装和使用
  • ZooKeeper 集群高可用配置指南
  • 在天嵌 TQ3568 (Debian) 上配置并添加打印机教程
  • pcl封装10 get_area_form_boundary计算平面点云面积
  • 突破局域网限制:MongoDB远程管理新体验
  • C++学习:map/set源码剖析+利用红黑树封装map/set
  • HTML开发工具有哪些?常用HTML编辑器推荐、HTML开发工具对比与HTML调试工具实战应用
  • Redis篇章3:Redis 企业级缓存难题全解--预热、雪崩、击穿、穿透一网打尽
  • 什么区块链(Blockchain)?Rust的区块链的例子
  • LangChain4J-(5)-记忆缓存与持久化
  • 遇到 npm install报错 certificate has expired是因为淘宝镜像源(registry.npm.taobao.org)