SpringBoot源码阅读(4)——事件
从监听器到事件
SpringApplication运行中触发事件,多播器发送事件到监听器,监听器处理事件。
SpingApplication中事件都是经过SpringApplicationRunListeners类传送到各个监听器。
以starting事件为例
void starting(ConfigurableBootstrapContext bootstrapContext, Class<?> mainApplicationClass) {doWithListeners("spring.boot.application.starting", (listener) -> listener.starting(bootstrapContext),(step) -> {if (mainApplicationClass != null) {step.tag("mainApplicationClass", mainApplicationClass.getName());}});
}
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();
}
这里的this.listeners是一个SpringApplicationRunListener的集合,而SpringApplicationRunListener的实现类配置中只有一个EventPublishingRunListener
starting事件执行的是EventPublishingRunListener的starting方法
public void starting(ConfigurableBootstrapContext bootstrapContext) {this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(bootstrapContext, this.application, this.args));
}
这里就找到了第一个事件ApplicationStartingEvent
接着往下执行
public void multicastEvent(ApplicationEvent event) {multicastEvent(event, resolveDefaultEventType(event));
}@Override
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));Executor executor = getTaskExecutor();for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {if (executor != null) {executor.execute(() -> invokeListener(listener, event));}else {invokeListener(listener, event);}}
}
ResolvableType类这里略过,里面涉及的内容较多,在这里的具体作用是从类的注解、泛型、继承结构、代理上获取原始的目标对象。
这里要注意的方法getApplicationListeners,根据事件类型获取监听器,然后执行。
查找的过程比较长,这里列举一些比较重要的方法
类AbstractApplicationEventMulticaster的getApplicationListeners、retrieveApplicationListeners、supportsEvent。
supportsEvent方法中有具体的判断逻辑
protected boolean supportsEvent(ApplicationListener<?> listener, ResolvableType eventType, @Nullable Class<?> sourceType) {GenericApplicationListener smartListener = (listener instanceof GenericApplicationListener ?(GenericApplicationListener) listener : new GenericApplicationListenerAdapter(listener));return (smartListener.supportsEventType(eventType) && smartListener.supportsSourceType(sourceType));
}
根据监听器的类型调用监听器类的支持事件类型supportsEventType和支持事件源类型supportsSourceType两个方法,来判断是否传播到该监听器。
ApplicationListener监听器有多个实现。
ClearCachesApplicationListenerParentContextCloserApplicationListenerFileEncodingApplicationListenerAnsiOutputApplicationListenerDelegatingApplicationListenerLoggingApplicationListenerEnvironmentPostProcessorApplicationListenerBackgroundPreinitializer
ClearCachesApplicationListener
结构:
implements ApplicationListener<ContextRefreshedEvent>
支持的事件类型:
ContextRefreshedEventApplicationContextEventApplicationEvent
支持的事件源:
无限制
ParentContextCloserApplicationListener
结构:
implements ApplicationListener<ParentContextAvailableEvent>, ApplicationContextAware, Ordered
支持的事件类型
ParentContextAvailableEventApplicationEvent
支持的事件源:
无限制
FileEncodingApplicationListener
结构:
implements ApplicationListener<ApplicationEnvironmentPreparedEvent>, Ordered
支持的事件类型:
ApplicationEnvironmentPreparedEventSpringApplicationEventApplicationEvent
支持的事件源:
无限制
AnsiOutputApplicationListener
结构:
implements ApplicationListener<ApplicationEnvironmentPreparedEvent>, Ordered
支持的事件类型:
ApplicationEnvironmentPreparedEventSpringApplicationEventApplicationEvent
支持的事件源:
无限制
DelegatingApplicationListener
结构:
implements ApplicationListener<ApplicationEvent>, Ordered
支持的事件类型:
ApplicationEvent
支持的事件源:
无限制
LoggingApplicationListener
结构:
implements GenericApplicationListener
支持的事件类型:
ApplicationStartingEventApplicationEnvironmentPreparedEventApplicationPreparedEventContextClosedEventApplicationFailedEvent
支持的事件源:
SpringApplicationApplicationContext
EnvironmentPostProcessorApplicationListener
结构:
implements SmartApplicationListener, Ordered
支持的事件类型:
ApplicationEnvironmentPreparedEventApplicationPreparedEventApplicationFailedEvent
支持的事件源:
SpringApplicationApplicationContext
BackgroundPreinitializer
结构:
implements ApplicationListener<SpringApplicationEvent>
支持的事件类型:
SpringApplicationEventApplicationEvent
支持的事件源:
无限制
事件
从EventPublishingRunListener的方法还有上面的事件类型,SpringBoot中的事件类型有:
ApplicationStartingEventApplicationEnvironmentPreparedEventApplicationContextInitializedEventApplicationPreparedEventApplicationStartedEventApplicationReadyEvent
除了multicastEvent多播事件,还有下面两个方法发布事件。
@Override
public void started(ConfigurableApplicationContext context, Duration timeTaken) {context.publishEvent(new ApplicationStartedEvent(this.application, this.args, context, timeTaken));AvailabilityChangeEvent.publish(context, LivenessState.CORRECT);
}@Override
public void ready(ConfigurableApplicationContext context, Duration timeTaken) {context.publishEvent(new ApplicationReadyEvent(this.application, this.args, context, timeTaken));AvailabilityChangeEvent.publish(context, ReadinessState.ACCEPTING_TRAFFIC);
}
事实上,这些事件都在一个包路径下。

ApplicationStartingEvent
注释:
事件在启动SpringApplication后尽早发布——在Environment或ApplicationContext可用之前,但在ApplicationListeners注册之后。事件的来源是SpringApplication本身,但要注意在早期阶段不要过多地使用其内部状态,因为它可能会在生命周期的后期被修改。
使用的翻译,不甚明了,得看看怎么这个事件触发后,监听器做了什么。
ApplicationEnvironmentPreparedEvent
注释:
当SpringApplication启动并且环境首次可用于检查和修改时发布的事件
ApplicationContextInitializedEvent
注释:
在启动SpringApplication、准备ApplicationContext和调用ApplicationContextInitializer时发布的事件,但在加载任何bean定义之前。
ApplicationPreparedEvent
注释:
当SpringApplication正在启动并且ApplicationContext已完全准备好但未刷新时发布的事件。将加载bean定义,并且环境已准备好在此阶段使用
ApplicationStartedEvent
注释:
刷新应用程序上下文后,但在调用任何应用程序和命令行运行程序之前发布的事件
ApplicationReadyEvent
注释:
事件尽可能晚地发布,以指示应用程序已准备好为请求提供服务。事件的来源是SpringApplication本身,但要注意修改其内部状态,因为届时所有初始化步骤都已完成
ApplicationFailedEvent
注释:
SpringApplication在启动失败时发布的事件
相关文章:
SpringBoot源码阅读(4)——事件
从监听器到事件 SpringApplication运行中触发事件,多播器发送事件到监听器,监听器处理事件。 SpingApplication中事件都是经过SpringApplicationRunListeners类传送到各个监听器。 以starting事件为例 void starting(ConfigurableBootstrapContext boo…...
EDI安全:如何在2024年保护您的数据免受安全和隐私威胁
电子数据交换(EDI)支持使用标准化格式在组织之间自动交换业务文档。这种数字化转型彻底改变了业务通信,消除了对纸质交易的需求并加速了交易。然而,随着越来越依赖 EDI 来传输发票、采购订单和发货通知等敏感数据,EDI …...
RabbitMQ快速入门 - 图像化界面的简单操作
目录 1、RabbitMQ的安装 2、RabbitMQ基本介绍 3、简单案例 4、数据隔离 1、RabbitMQ的安装 官网链接:rabbitmq官网 (官网很详细,也可以在官网学习啦~) 基础入门:自主学习:最新版本:安装我…...
新版亚组交互效应函数(P for interaction)newscitb5 1.3版本发布--用于一键生成交互效应表
在SCI文章中,交互效应表格(通常是表五)能为文章锦上添花,增加文章的信服力,增加结果的可信程度,还能进行数据挖掘。什么是亚组,通常就是特殊类型人群,比如男女,种族等&am…...
gpt讲 Observable 对象
什么是 Observable? Observable 是一种用于处理异步数据流的数据类型。它可以发出多个值,这些值可以是同步或者异步产生的,并且可以在时间上发生变化。在 Angular 中,HttpClient 返回的响应对象、事件流以及许多其他异步任务都可…...
STM32的SPI接口详解
目录 1.SPI简介 2.SPI工作原理 3.SPI时序 3.1 CPOL(Clock Polarity,时钟极性): 3.2 CPHA(Clock Phase,时钟相位): 3.3 四种工作模式 4.相关代码 4.1使能片选信号 4.2使能通…...
谷歌+火狐浏览器——实现生成二维码并实现拖动——js技能提升
最新遇到的问题:前两个二维码拖动不了,只有第三个一维码生成后,才可以拖拽 【问题】:出现在都是绝对定位,但是没有指定z-index导致的。 解决办法:在方法中添加一个变量 renderDrag(id) {var isDragging f…...
128陷阱详解(从源码分析)
1、128陷阱描述 Integer 整型 -128~127 超过这个范围,比较会不准确 例子 public static void main(String[] args) {Integer a128;Integer b128;Integer e127;Integer f127;System.out.println(ab); //输出falseSystem.out.println(a.equals(b)); //输出trueS…...
点云处理实操 基于多项式重构的平滑和法线估计
目录 基于多项式重构的平滑和法线估计 一、什么是移动最小二乘法(Moving Least Squares, MLS) 二、算法原理 三、算法应用 四、PCL代码实践 基于多项式重构的平滑和法线估计 原文地址:Smoothing and normal estimation based on polynomial reconstruction — Point Cl…...
MongoDB在Linux下的安装与基本操作指南
MongoDB是一款高性能、开源的NoSQL数据库系统,特别适合处理大规模数据存储应用。本文将详细介绍MongoDB在Linux系统(以Ubuntu为例)上的安装步骤,以及如何进行基本的数据库操作,帮助你快速上手MongoDB。 一、在Linux上…...
端口占用快速解决
netstat -aon|findsstr 8989 taskkill /pid 13221 -t -f 命令解释 1.检查网络连接状态 2.终止特定进程 netstat -aon | findstr 8989 netstat: 这是一个网络状态统计工具,可以显示活动的网络连接、路由表、接口表、多播成员信息等。-a: 显示所有连接和监听端口。通…...
普中51单片机:矩阵按键扫描与应用详解(五)
文章目录 引言电路图开发板IO连接矩阵键盘的工作原理行列扫描逐行/逐列扫描 LCD1602代码库代码演示——暴力扫描代码演示——数码管(行列式)代码演示——线翻转法代码演示——LCD1602密码锁 引言 矩阵按键是一种通过行列交叉连接的按键阵列,可以有效地减少单片机I/…...
SQLite Glob 子句
SQLite Glob 子句 SQLite 的 GLOB 子句是一种强大的搜索工具,用于在数据库中执行模式匹配操作。它类似于 SQL 中的 LIKE 子句,但 GLOB 使用的是基于文件系统的通配符,而不是 SQL 的百分比 (%) 和下划线 (_) 通配符。在本文中,我们…...
Redis基础教程(十七):Redis数据备份与恢复
💝💝💝首先,欢迎各位来到我的博客,很高兴能够在这里和您见面!希望您在这里不仅可以有所收获,同时也能感受到一份轻松欢乐的氛围,祝你生活愉快! 💝Ὁ…...
基于FPGA的千兆以太网设计(1)----大白话解释什么是以太网
1、什么是以太网? 还记得初学以太网的时候,我就被一大堆专业名词给整懵了:什么以太网,互联网,MAC,IP,局域网,万维网,网络分层模型等等等等。慢着!我学的不是以太网吗?怎么出来这么一大堆东西? 啊!以太网究竟是什么?别急,我接下来就尽量用通俗的大白话来给你解释…...
wordpress的restfull API使用教程,之如何用postman调试API,以便能使用vue等前端框架开发主题
文章目录 API开发手册在postman中调试这里以 post 一篇文章为例,讲解如何调试: 步骤 1:生成应用密码步骤 2:配置Postman步骤 3:创建文章 参考链接 API开发手册 官方API手册:https://developer.wordpress.o…...
刷题刷题刷题
P1123 取数游戏 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 思路: 从1,1开始dfs,若行数x>n则立马刷新最大值退出搜索,若y>m则进入下一行从第一列开始搜索即x1,y1,对当前的搜索点x,y的八个方向进行1,因为不能相邻 AC:…...
【Spring Boot】统一异常处理
目录 统一异常处理一. 概念二. 全局异常处理三. 处理特定异常 统一异常处理 一. 概念 其实统一异常是运用了AOP(对某一类事情的集中处理)的思维,简单概括就是在我们进行前后端数据交互的时候,抛出的任何的异常都能够自动捕获然后…...
java —— tomcat 部署项目
一、通过 war 包部署 1、将项目导出为 war 包; 2、将 war 包放置在 tomcat 目录下的 webapps 文件夹下,该 war 包稍时便自动解析为项目文件夹; 3、启动 tomcat 的 /bin 目录下的 startup.bat 文件,此时即可从浏览器访问项目首页…...
数据库的优点和缺点分别是什么
数据库作为数据存储和管理的核心组件,具有一系列显著的优点,同时也存在一些潜在的缺点。以下是对数据库优点和缺点的详细分析: 数据库的优点 数据一致性:数据库通过事务管理、锁机制、并发控制等技术手段,确保多个用户…...
Prompt Tuning、P-Tuning、Prefix Tuning的区别
一、Prompt Tuning、P-Tuning、Prefix Tuning的区别 1. Prompt Tuning(提示调优) 核心思想:固定预训练模型参数,仅学习额外的连续提示向量(通常是嵌入层的一部分)。实现方式:在输入文本前添加可训练的连续向量(软提示),模型只更新这些提示参数。优势:参数量少(仅提…...
Admin.Net中的消息通信SignalR解释
定义集线器接口 IOnlineUserHub public interface IOnlineUserHub {/// 在线用户列表Task OnlineUserList(OnlineUserList context);/// 强制下线Task ForceOffline(object context);/// 发布站内消息Task PublicNotice(SysNotice context);/// 接收消息Task ReceiveMessage(…...
可靠性+灵活性:电力载波技术在楼宇自控中的核心价值
可靠性灵活性:电力载波技术在楼宇自控中的核心价值 在智能楼宇的自动化控制中,电力载波技术(PLC)凭借其独特的优势,正成为构建高效、稳定、灵活系统的核心解决方案。它利用现有电力线路传输数据,无需额外布…...
鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院挂号小程序
一、开发准备 环境搭建: 安装DevEco Studio 3.0或更高版本配置HarmonyOS SDK申请开发者账号 项目创建: File > New > Create Project > Application (选择"Empty Ability") 二、核心功能实现 1. 医院科室展示 /…...
【ROS】Nav2源码之nav2_behavior_tree-行为树节点列表
1、行为树节点分类 在 Nav2(Navigation2)的行为树框架中,行为树节点插件按照功能分为 Action(动作节点)、Condition(条件节点)、Control(控制节点) 和 Decorator(装饰节点) 四类。 1.1 动作节点 Action 执行具体的机器人操作或任务,直接与硬件、传感器或外部系统…...
【Oracle】分区表
个人主页:Guiat 归属专栏:Oracle 文章目录 1. 分区表基础概述1.1 分区表的概念与优势1.2 分区类型概览1.3 分区表的工作原理 2. 范围分区 (RANGE Partitioning)2.1 基础范围分区2.1.1 按日期范围分区2.1.2 按数值范围分区 2.2 间隔分区 (INTERVAL Partit…...
学习STC51单片机32(芯片为STC89C52RCRC)OLED显示屏2
每日一言 今天的每一份坚持,都是在为未来积攒底气。 案例:OLED显示一个A 这边观察到一个点,怎么雪花了就是都是乱七八糟的占满了屏幕。。 解释 : 如果代码里信号切换太快(比如 SDA 刚变,SCL 立刻变&#…...
Android第十三次面试总结(四大 组件基础)
Activity生命周期和四大启动模式详解 一、Activity 生命周期 Activity 的生命周期由一系列回调方法组成,用于管理其创建、可见性、焦点和销毁过程。以下是核心方法及其调用时机: onCreate() 调用时机:Activity 首次创建时调用。…...
Bean 作用域有哪些?如何答出技术深度?
导语: Spring 面试绕不开 Bean 的作用域问题,这是面试官考察候选人对 Spring 框架理解深度的常见方式。本文将围绕“Spring 中的 Bean 作用域”展开,结合典型面试题及实战场景,帮你厘清重点,打破模板式回答,…...
Xela矩阵三轴触觉传感器的工作原理解析与应用场景
Xela矩阵三轴触觉传感器通过先进技术模拟人类触觉感知,帮助设备实现精确的力测量与位移监测。其核心功能基于磁性三维力测量与空间位移测量,能够捕捉多维触觉信息。该传感器的设计不仅提升了触觉感知的精度,还为机器人、医疗设备和制造业的智…...
