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

一文讲懂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.mrgr.cn/news/22205.html

相关文章:

  • Redis访问工具
  • 【Java 优选算法】双指针(上)
  • 【Dart 教程系列第 50 篇】在 Flutter 项目的国际化多语言中,如何根据翻译提供的多语言文档表格,快速生成不同语言的内容
  • 计算机毕业设计选题推荐-宠物店管理系统-Java/Python项目实战
  • JVM 调优篇4 jvm的垃圾回收中垃圾日志的阅读查看2
  • 【系统架构设计师】管道-过滤器架构
  • 单片机毕业设计-基于单片机的运动手环
  • 深入理解Oracle数据库中的数据库链接
  • 【verilog】1. 流水灯例程
  • Ascend C算子开发(中级)—— 编写Sinh算子
  • 秒懂:进程优先级
  • linux日常使用命令总结
  • Java XML
  • AtCoder Beginner Contest 370 ABCD题详细题解(C++,Python)
  • 拓扑排序-广度优先遍历思路
  • proxy代理解决vue中跨域问题
  • 数据结构与算法 第12天(排序)
  • VLAN配置学习笔记
  • mac m2 安装 nvm
  • 基于yolov8的肺炎检测系统python源码+onnx模型+评估指标曲线+精美GUI界面