一文讲懂Spring Event事件通知机制

目录

一 什么是spring event

二 怎么实现spring event


一 什么是spring event

        我不会按照官方的解释来说什么是spring event,我只是按照自己的理解来解释,可能原理上会和官方有偏差,但是它的作用和功能就是这个,我更加偏向于从他的功能方面去解释,官方的解释其实有点听不懂。

        ok,说了这么多,到底什么是spring event?我相信event大家都很熟悉,就是事件,那么我么在学前端的时候肯定都知道事件,最常用的就是点击事件,点击一个按钮就触发一个事件。我觉得这里也可以这么理解,只是区别在于这里没有按钮,所以我们只能监听,比如当某个条件达成后,就会自动触发事件。所以,我对于spring event理解就是这样。只是这个监听的对象,在接下来我将一步一步给大家讲清楚。

二 怎么实现spring event

        正如我上面所说的,spring event本身的功能不过就是监听我们设置的某个条件如果触发了,那么就会触发事件,然后执行我们想要执行的代码逻辑。那么很简单,我们只需要定义一个事件监听器,然后监听某个事件,当这个事件被触发,我们就可以执行监听器里面的代码逻辑。

        没错,代码也确实如此,spring提供了一个 ApplicationListener<xxx>接口。只要实现这个接口,就相当于一个事件监听器,尖括号里面的就是我们监听的事件对象,当这个监听的对象达到条件,这个接口里面有一个onApplicationEvent()方法就会被执行,然后我们可以在里面实现我们的逻辑。

        至于监听的对象,我们使用spring的初始化的一些事件,大概都有如下事件:

  1. ContextRefreshedEvent: 当应用程序上下文(ApplicationContext)初始化或刷新完成后触发。这通常发生在应用程序启动过程中,并且表示应用程序已准备好接收请求和执行业务逻辑。可以使用该事件来执行一些初始化操作,例如加载缓存数据、启动后台任务等。

  2. ContextStartedEvent: 当应用程序上下文启动时触发。这个事件在调用 ConfigurableApplicationContext 的 start() 方法后被发布。可以使用该事件来执行启动应用程序所需的特定逻辑,例如启动定时任务、启动消息监听器等。

  3. ContextStoppedEvent: 当应用程序上下文停止时触发。这个事件在调用 ConfigurableApplicationContext 的 stop() 方法后被发布。可以使用该事件来执行停止应用程序所需的清理逻辑,例如关闭连接、释放资源等。

  4. ContextClosedEvent: 当应用程序上下文关闭时触发。这个事件在调用 ConfigurableApplicationContext 的 close() 方法后被发布。可以使用该事件来执行一些最终的清理操作,例如释放数据库连接、销毁单例对象等。

  5. ServletRequestHandledEvent: 当 Spring MVC 处理完一个 HTTP 请求时触发。该事件提供了有关请求处理的详细信息,包括请求的处理时间、处理器、处理器适配器等。可以使用该事件来进行请求处理的监控、日志记录或统计信息收集等操作。

  6. ApplicationStartedEvent(Spring Boot): 当 Spring Boot 应用程序启动时触发。这个事件在 SpringApplication.run() 方法完成后被发布。可以使用该事件来执行特定于应用程序的初始化逻辑。

  7. ApplicationReadyEvent(Spring Boot): 当 Spring Boot 应用程序准备就绪时触发。这个事件表示应用程序已经启动完毕,并且已经可以提供服务。可以使用该事件来执行应用程序的后续初始化操作,例如加载数据、发送通知等。

我们这里就以 ContextRefreshedEvent 当程序上下文初始化后触发这个事件为例,代码如下:

package com.feisi.test.event;import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;@Component
public class MyApplicationLister implements ApplicationListener<ContextRefreshedEvent> {@Overridepublic void onApplicationEvent(ContextRefreshedEvent event) {System.out.println("容器上下文初始化完成后监听器触发,触发的事件源为:"+event.getSource());}
}

到这里,其实我们就完成了一个事件监听的功能。

但是!!!

我们现在思考一个问题,我们上面这个监听器,当spring上下文初始化后执行监听器,既然是这样,那么我们肯定是需要初始化一些数据,比如往redis缓存一些初始化数据等等,或者是我们自定义的一些数据。

但是上面这个示例,我们得到的参数只是事件源对象,但这个事件源对象,是spring给我们提供,我们肯定没办法自定义我们想要的数据。所以我们想要自定义我们需要的数据,那么只能自己定义一个事件源对象。

但是我们自定义了一个数据源对象,怎么才能发布这个对象呢?

这里我们再来解释一下上面那个示例的执行原理,我们的事件源对象是ContextRefreshEvent,当spring上下文对象 初始化完成后,spring就会自动帮我们发布这个事件,或者是说注册这个事件,这个时候,它就会通知所有spring容器里面实现了监听器接口(ApplicationList)并且监听的事件源对象是ContextRefreshEvent的Bean对象,也就是上面我定义的这个监听器对象,那么它满足条件就会收到这个信号,它就会被执行onApplicationEvent方法。

那么到这里,我们已经明白整个执行流程,那么我现在是不是可以自定义一个事件,并且在里面可以自定我们想要的数据,然后在我上面示例的基础上,我们把onApplicationEvent方法里面的逻辑改成发布/注册我们自定义的事件对象,然后,我们再创建一个监听器类,但是这个监听器类监听的事件源对象是我们自定义的对象,这样我们自定义的事件对象被发布后,那么监听我们自定义事件源的监听器就会被触发,然后执行里面onApplicationEvent方法,这样传来的参数就是我们自定义的事件源对象,这样该对象里面肯定就会有我们自定义的数据,我们就完成了对自定义数据的处理。

所以,在上面的基础上,我们自定义一个事件源对象。

package com.feisi.test.event;import lombok.Data;
import org.springframework.context.ApplicationEvent;import java.time.Clock;public class MyApplicationEvent extends ApplicationEvent {private String name ;public String getName() {return name;}public void setName(String name) {this.name = name;}/*** 必须要生成有参构造函数* @param source 发布这个事件的监听器* @param name  我们传入我们自定义的参数*/public MyApplicationEvent(Object source, String name) {super(source);this.name = name ; }
}

自定义事件对象完成后,我们需要把上面示例中的监听器里面的onApplicationEvent方法中的逻辑代码改一下。应该改成,当容器上下文初始化完成后,调用这个方法,然后在这个方法发布我们自定义的事件对象。

package com.feisi.test.event;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;import java.util.concurrent.atomic.AtomicBoolean;@Component
public class MyApplicationLister implements ApplicationListener<ContextRefreshedEvent> {@Autowiredprivate ApplicationContext applicationContext ; //用于发布我们自定义的事件对象private AtomicBoolean flag = new AtomicBoolean(false);  // 用于防止二次触发事件@Overridepublic void onApplicationEvent(ContextRefreshedEvent event) {System.out.println("容器初始化完成后,触发事件....");//发布我们自定义的事件if(flag.compareAndSet(false,true)){  //true: 修改成功  false: 没修改applicationContext.publishEvent(new MyApplicationEvent(this,"zhangsan"));}}
}

 

到这里,当spring初始化完成后,就会触发监听器,然后将我们自定义的事件发布,这个时候,spring就会通知自己容器里面所有的bean,如果你实现了ApplicationEvent事件监听器接口,并且你监听的对象是刚刚已经发布的MyApplicatioinEvent对象,那么你就已经达到了触发的调用,就会被自动执行。

所以,我们现在只需要再自定义一个类实现监听器接口,并且监听我们自定义的事件对象,我们这个监听器就会被触发,我们传入的参数也是我们自定义的事件,我们就可以执行相关的逻辑代码:

package com.feisi.test.demo;import com.feisi.test.event.MyApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;@Component
public class MyApplicationEventListerTest implements ApplicationListener<MyApplicationEvent> {@Overridepublic void onApplicationEvent(MyApplicationEvent event) {System.out.println("自定义事件源发布,开始触发事件,初始化自定义数据:"+event.getName());}
}

整体大概执行流程图如下:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/53398.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Rust:Restful API 服务程序开发详述

0. 关于异步程序设计 0.1 对异步机制的理解 运行效率对于后端程序来讲很重要。我曾经以为&#xff0c;多线程机制是后端设计的终极方法&#xff0c;后来才发现&#xff0c;异步机制才是榨干 CPU 运行效率资源的关键所在。 我最初对于异步程序设计有误解&#xff0c;以为多线…

详解React setState调用原理和批量更新的过程

1. React setState 调用的原理 setState目录 1. React setState 调用的原理2. React setState 调用之后发生了什么&#xff1f;是同步还是异步&#xff1f;3. React中的setState批量更新的过程是什么&#xff1f; 具体的执行过程如下&#xff08;源码级解析&#xff09;&#x…

安卓13带有系统签名的应用不能正常使用webview 调用webview失败 系统应用app apk

总纲 android13 rom 开发总纲说明 文章目录 1.前言2.问题分析3.代码分析4.代码修改5.彩蛋1.前言 android版本高一些的平台,经常会遇到一些权限安全问题,像客户的应用如果带有系统签名,会导致不能正常使用webview问题。 2.问题分析 我们log信息,可以发现下面的提示: Fo…

网络层ip协议

一.概念 ip协议主要是为了在复杂的网络环境中确定一个合适的路径来传输主机间的数据。简单来说就是用来确定主机的位置。 ip协议中的一些设备如下&#xff1a; 主机: 配有 IP 地址, 但是不进行路由控制的设备;路由器: 即配有 IP 地址, 又能进行路由控制;节点: 主机和路由器的统…

分库分表:应对大数据量挑战的数据库扩展策略

随着互联网技术的发展&#xff0c;数据量的爆炸性增长给数据库系统带来了前所未有的挑战。为了有效管理大规模数据并保持高性能&#xff0c;分库分表成为了一种常见的数据库扩展策略。本文将探讨分库分表的概念、动机、实施策略以及潜在的挑战和解决方案。 什么是分库分表&…

传统CV算法——边缘算子与图像金字塔算法介绍

边缘算子 图像梯度算子 - Sobel Sobel算子是一种用于边缘检测的图像梯度算子&#xff0c;它通过计算图像亮度的空间梯度来突出显示图像中的边缘。Sobel算子主要识别图像中亮度变化快的区域&#xff0c;这些区域通常对应于边缘。它是通过对图像进行水平和垂直方向的差分运算来…

5.2.数据结构-c/c++二叉树详解(下篇)(算法面试题)

本章所有代码请见&#xff1a;5.3.数据结构-c/c二叉树代码-CSDN博客 上篇:5.数据结构-c/c二叉树详解(上篇)&#xff08;遍历方法&#xff0c;完全二叉树&#xff09;-CSDN博客 目录 1 求二叉树 第k层的节点 2 查找一个节点是否在二叉树中 3 求二叉树节点的个数 4 求二叉树…

Linux 删除 当前下的 mysql-8.0.31 空文件夹

在Linux中&#xff0c;如果你想要删除当前目录下的名为mysql-8.0.31的空文件夹&#xff08;即该文件夹内没有任何文件或子文件夹&#xff09;&#xff0c;你可以使用rmdir命令。但是&#xff0c;如果mysql-8.0.31文件夹并非完全为空&#xff08;即它包含文件或子文件夹&#xf…

在js中观察者模式讲解

在JavaScript中,观察者模式(Observer Pattern)是一种设计模式,允许一个对象(被观察者,Subject)维护一个依赖它的对象列表(观察者,Observer),并在它自身状态发生变化时自动通知这些观察者。观察者模式的典型使用场景包括事件系统、数据绑定和实时更新等情况。 一 、…

.Net Core 笔试1

1、用两个线程一个输出字母一个输出数字&#xff0c;交替输出Chat数组 char[] aI "1234567".ToCharArray();char[] aC "ABCDEFG".ToCharArray();Task task1 null;Task task2 null;task1 Task.Run(() >{foreach (var item in aI){Console.WriteLine…

数据结构(邓俊辉)学习笔记】排序 1——快速排序:算法A

文章目录 1. 分而治之2. 轴点3. 构造轴点4. 单调性 不变性5. 实例 1. 分而治之 主题就是排序。实际上我们对于排序问题并不陌生。你应该记得在最开始的几章&#xff0c;我们就分别介绍过起泡排序、插入排序、选择排序以及归并排序&#xff0c;而在介绍散列技术时&#xff0c;我…

自定义TextView实现结尾加载动画

最近做项目&#xff0c;仿豆包和机器人对话的时候&#xff0c;机器人返回数据是流式返回的&#xff0c;需要在文本结尾添加加载动画&#xff0c;于是自己实现了自定义TextView控件。 源码如下&#xff1a; import android.content.Context import android.graphics.Canvas imp…

Html、Css3动画效果

文章目录 第九章 动画9.1 transform动画9.2 transition过渡动画9.3 定义动画 第九章 动画 9.1 transform动画 transform 2D变形 translate()&#xff1a;平移函数&#xff0c;基于X、Y坐标重新定位元素的位置 scale()&#xff1a;缩放函数&#xff0c;可以使任意元素对象尺…

【系统架构设计师-2010年】综合知识-答案及详解

更多内容请见: 备考系统架构设计师-核心总结索引 文章目录 【第1题】【第2题】【第3题】【第4~5题】【第6题】【第7~8题】【第9题】【第10题】【第11题】【第12题】【第13题】【第14题】【第15题】【第16题】【第17题】【第18题】【第19题】【第20题】【第21题】【第22题】【第…

高斯平面直角坐标讲解,以及地理坐标转换高斯平面直角坐标

高斯平面直角坐标系(Gauss-Krger 坐标系)是基于 高斯-克吕格投影 的一种常见的平面坐标系统,主要用于地理信息系统 (GIS)、测绘和工程等领域。该坐标系将地球表面的经纬度(地理坐标)通过一种投影方式转换为平面直角坐标,以便在二维平面中进行距离、面积和角度的计算。 一…

自动化抢票 12306

自动化抢票 12306 1. 明确需求 明确采集的网站以及数据内容 网址: https://kyfw.12306.cn/otn/leftTicket/init数据: 车次相关信息 2. 抓包分析 通过浏览器开发者工具分析对应的数据位置 打开开发者工具 F12 或鼠标右键点击检查 刷新网页 点击下一页/下滑网页页面/点击搜…

基于云原生向量数据库 PieCloudVector 的 RAG 实践

近年来&#xff0c;人工智能生成内容&#xff08;AIGC&#xff09;已然成为最热门的话题之一。工业界出现了各种内容生成工具&#xff0c;能够跨多种模态产生多样化的内容。这些主流的模型能够取得卓越表现&#xff0c;归功于创新的算法、模型规模的大幅扩展&#xff0c;以及海…

HalconDotNet中的图像特征与提取详解

文章目录 简介一、边缘特征提取二、角点特征提取三、区域特征提取四、纹理特征提取五、形状特征提取 简介 图像特征提取是图像处理中的一个重要步骤&#xff0c;用于从图像中提取有意义的特征&#xff0c;以便进行进一步的分析和处理。HalconDotNet提供了多种图像特征提取方法&…

用Boot写mybatis的增删改查

一、总览 项目结构&#xff1a; 图一 1、JavaBean文件 2、数据库操作 3、Java测试 4、SpringBoot启动类 5、SpringBoot数据库配置 二、配置数据库 在项目资源包中新建名为application.yml的文件&#xff0c;如图一。 建好文件我们就要开始写…

【MySQL00】【 杂七杂八】

文章目录 一、前言二、MySQL 文件1. 参数文件2. 日志文件3. 套接字文件4. pid 文件5. 表结构定义文件6. InnoDB 存储引擎文件 二、BTree 索引排序三、InnoDB 关键特性1. 插入缓冲1.1 Insert Buffer 和 Change Buffer1.1 缓冲合并 2. 两次写2. 自适应哈希索引3. 异步IO4. 刷新邻…