Spring事件机制让你的代码更优雅

news2024/12/26 14:05:22

今天为大家分享一下Spring的事件机制的使用,它是spring中一个非常好用也很实用的机制。

1. spring事件机制的概念

Spring的事件机制是基于观察者模式实现的,它可以在我们的实际应用程序中实现代码之间的解耦,提高代码的可维护性和可扩展性。

Spring的事件机制包括事件、事件发布、事件监听器等几个基本概念。

  • 事件是一个抽象的概念,它代表着应用程序中的某个动作或状态的发生。
  • 事件发布是事件发生的地方,它负责产生事件并通知事件监听器。
  • 事件监听器是事件的接收者,它负责处理事件并执行相应的操作。

在Spring的事件机制中,事件源和事件监听器之间可以通过事件进行通信,来实现模块之间的解耦,提高代码的优雅性和可维护性。

比如:用户修改密码,需要进行短信通知,记录关键性日志或者其他业务操作。
在这里插入图片描述

1.1 事件

通过继承ApplicationEvent,实现自定义事件。Spring 中的所有事件都要基于其进行扩展。其源码如下:
在这里插入图片描述

1.2 事件发布

事件发布是事件发生地,它负责产生事件并通知事件监听器。ApplicationEventPublisher用于发布 ApplicationEvent 事件,发布后 ApplicationListener 才能监听到事件进行处理。源码如下:
在这里插入图片描述

参数需要一个ApplicationEvent,就是我们的事件,然后通过该方法去发布我们的事件。

1.3 事件监听器

ApplicationListener 是 Spring 事件的监听器,用来接受事件,所有的监听器都必须实现该接口。该接口源码如下:
在这里插入图片描述

或者采用注解方式来实现:@EventListener。

2. 案例演示

2.1 定义事件

/**
 * @BelongsProject: ims-formworkflow-api
 * @BelongsPackage: com.wuk.imsformworkflowapi.client
 * @Author: wuk
 * @Date: 2023/6/13 9:54
 * @Description: 创建事件
 */
@Getter
@Setter
public class UserChangePasswordEvent extends ApplicationEvent {

    private String userId;

    public UserChangePasswordEvent(String userId) {
        super(new Object());
        this.userId = userId;
    }
}

这里就定义我们监听器需要的业务参数,我们需要监听器监听哪些参数的变化,我们就在这里定义哪些参数。

2.2 监听事件的实现

有两种方式,一种是通过实现接口方式,一种是注解方式,推荐使用注解,耦合性比较低,比较灵活。
方式一:

/**
 * @BelongsProject: ims-formworkflow-api
 * @BelongsPackage: com.wuk.imsformworkflowapi.client
 * @Author: wuk
 * @Date: 2023/6/13 9:57
 * @Description: 方式1:实现接口方式,实现监听逻辑
 */
@Component
public class MessageListener implements ApplicationListener<UserChangePasswordEvent> {
    @Override
    public void onApplicationEvent(UserChangePasswordEvent event) {
        System.out.println("监听者1:收到事件:" + event);
        System.out.println("监听者1:开始执行业务操作给用户发送短信。用户userId为:" + event.getUserId());
    }
}

方式二:

/**
 * @BelongsProject: ims-formworkflow-api
 * @BelongsPackage: com.wuk.imsformworkflowapi.client
 * @Author: wuk
 * @Date: 2023/6/13 10:24
 * @Description: 方式二:注解形式实现事件监听器
 */
@Component
public class ListenerEvent {

    @EventListener({ UserChangePasswordEvent.class })
    public void LogListener(UserChangePasswordEvent event) {
        System.out.println("监听者2:收到事件:" + event);
        System.out.println("监听者2:开始执行业务操作生成关键日志。用户userId为:" + event.getUserId());
    }

    @EventListener({ UserChangePasswordEvent.class })
    public void messageListener(UserChangePasswordEvent event) {
        System.out.println("监听者3:收到事件:" + event);
        System.out.println("监听者3:开始执行业务操作给用户发送短信。用户userId为:" + event.getUserId());
    }
}

注意:使用 @EventListener 注解的好处是一个类可以写很多监听器,定向监听不同的事件,或者同一个事件。

这里面还延伸了一个注解:@TransactionalEventListener,他与@EventListener不同的就是@EventListener标记一个方法作为监听器,他默认是同步执行

我们知道,Spring的事件监听机制实际上是同步的。来将代码进行解耦。而@TransactionEventListener仍是通过这种方式,但是加入了回调的方式来解决,这样就能够在事务进行Commited,Rollback…等时候才去进行Event的处理,来达到事务同步的目的。

2.3 事件发布

    @GetMapping("/eventTest")
    public R<Void> eventTest(){

        applicationEventPublisher.publishEvent(new UserChangePasswordEvent("11111"));

        return R.ok();
    }

执行完毕后,控制台打印如下:
在这里插入图片描述

3. 利用@Async实现事件异步

监听器默认是同步执行的,如果我们想实现异步执行,可以搭配@Async注解使用。

注意:使用@Async时,需要配置线程池,否则用的还是默认的线程池也就是主线程池,线程池使用不当会浪费资源,严重的会出现OOM事故。

我这边只做演示,就不创建线程池了。

3.1 启动类添加@EnableAsync开启异步执行配置

@EnableAsync
@SpringBootApplication
public class SpirngEventApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpirngEventApplication.class, args);
    }

}

3.2 在要异步执行的监听器上添加@Async注解

@Component
public class ListenerEvent {
    
    @Async
    @EventListener({ UserChangePasswordEvent.class })
    public void logListener(UserChangePasswordEvent event) {
        System.out.println("收到事件:" + event);
        System.out.println("开始执行业务操作生成关键日志。用户userId为:" + event.getUserId());
    }
}

4. 场景应用

  • 告警操作,比如钉钉飞书告警,异常告警,可以通过事件机制进行解耦。
  • 关键性日志记录和业务埋点。
  • 性能监控,比如说接口的时长,性能方便的监控等。可以通过事件机制进行解耦。

总之与主业务无关的操作都可以通过这种方式进行解耦。

5. 注意点

在使用spring事件中我们要注意如下问题:

  • 对于同一个事件,有多个监听器的时候,可以通过@Order注解指定顺序,Order的value值越小,执行的优先级就越高。
  • 如果发布事件的方法处于事务中,那么事务会在监听器方法执行完毕之后才提交。事件发布之后就由监听器去处理,而不要影响原有的事务,也就是说希望事务及时提交。我们就可以 @TransactionalEventListener来定义一个监听器。
  • 监听器默认是同步执行的,如果我们想实现异步执行,可以搭配@Async注解使用。
  • 对于同一个事件,有多个监听器的时候,如果出现了异常,后续的监听器就失效了,因为他是把同一个事件的监听器add在一个集合里面循环执行,如果出现异常,需要注意捕获异常处理异常。

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

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

相关文章

ShardingSphere-Proxy 分库分表

安装ShardingSphere-Proxy 中间件封装 定位为透明化的数据库代理端&#xff0c;提供封装了数据库二进制协议的服务端版本&#xff0c;用于完成对异构语言的支持。 目前提供 MySQL 和 PostgreSQL版本&#xff0c;它可以使用任何兼容 MySQL/PostgreSQL 协议的访问客户端&#x…

面试必问:四种经典限流算法

今天给大家分享一下限流方面的&#xff0c;大家都知道&#xff0c;在分布式系统中&#xff0c;高并发场景下&#xff0c;为了防止系统因突然的流量激增而导致的崩溃&#xff0c;同时保证服务的高可用性和稳定性&#xff0c;限流是最常用的手段。希望能够给大家带来帮助&#xf…

STM32常见面试题

一、STM32F1和F4的区别&#xff1f; 内核不同&#xff1a;F1是Cortex-M3内核&#xff0c;F4是Cortex-M4内核&#xff1b; 主频不同&#xff1a;F1主频72MHz&#xff0c;F4主频168MHz&#xff1b; 浮点运算&#xff1a;F1无浮点运算单位&#xff0c;F4有&#xff1b; 功能性能&…

【无标题】vue中表单绑定v-model

表单绑定v-model 表单控件在实际开发中是非常常见的。特别是对于用户信息的提交&#xff0c;需要大量的表单。 Vue中使用v-model指令来实现表单元素和数据的双向绑定。 案例的解析&#xff1a; 当我们在输入框输入内容时 因为input中的v-model绑定了message&#xff0c;所以会…

Vue-搭建Vuex开发环境

1 安装Vuex 安装之前需要了解一个版本问题&#xff0c;在vue2中&#xff0c;要用vuex的3版本&#xff0c;在vue3中&#xff0c;要用vuex的4版本&#xff0c;要严格遵循这个版本要求&#xff0c;不然就会出现各种意想不到的问题&#xff0c;例如下方安装报错&#xff0c;就算因…

ubuntu修改应用图表|任务栏收藏|快捷方式|收藏夹

需要知道应用程序对应的.desktop文件的位置&#xff0c;然后使用sudo gedit打开。修改对应位置的信息就可以了。 参考&#xff1a;Linux下Desktop文件入门 1.desktop文件位置 一般存放在/usr/share/applications这个位置里面。 以vscode为例&#xff0c;使用sudo gedit code…

POJ - 2287 Tian Ji -- The Horse Racing

题目来源 2287 -- Tian Ji -- The Horse Racing (poj.org) 题目描述 田忌赛马是中国历史上一个著名的故事。 这个故事发生在2300年前&#xff0c;田忌是齐国的一个大官&#xff0c;他喜欢和齐王以及其他公子赛马。 田忌和齐王都有三类马&#xff0c;分别是下等马&#xff0…

1750_使用gcc对嵌入式代码控制逻辑进行测试

全部学习汇总&#xff1a; GreyZhang/c_basic: little bits of c. (github.com) 相信很多人的C语言学习是从printf开始的&#xff0c;为了验证我们的程序代码运行结果&#xff0c;我们通常会选择使用printf打印出我们计算的结果看一下是否与预期一致。到了嵌入式软件开发&#…

web前端工程师个人简历编写(附详细代码)

web前端工程师 h5css3完成简历编写&#xff0c;效果如下&#xff1a; 底部附有详细代码编写 编写Web前端工程师个人简历时&#xff0c;需要注意以下几点&#xff1a; 简洁明了&#xff1a;简历应该简洁明了&#xff0c;内容要点突出&#xff0c;避免冗长和废话。用简洁的语言…

Boost的介绍、安装与环境配置

文章目录 一、Boost库简介二、Boost的安装与编译&#xff08;一&#xff09;下载解压&#xff08;二&#xff09;编译静态库 三、配置VS环境四、其它环境的配置&#xff08;vscode、DevC&#xff09;&#xff08;一&#xff09;在DEVC中配置使用boost库的环境&#xff08;二&am…

java: 程序包javax.servlet.http不存在

问题描述 当项目从2.7.x的springboot升级到3.0.x的时候&#xff0c;遇到一个问题“java: 程序包javax.servlet.http不存在” 。这可能是一些包的精简变化导致的。错误信息如下&#xff1a; 错误代码段 package com.softdev.system.generator.config;import com.softdev.system…

深度学习-ubuntu18.04+RTX3080+cuda11.2+cudnn8.1.0下安装polarstream全纪录

&#xff11;、安装 创建一个python3.7的虚拟环境 conda create --name polarstream python3.7 激活虚拟环境 source activate polarstream以下操作均在虚拟环境中进行 安装与cuda和python版本对应的torch版本,参考https://blog.csdn.net/didadifish/article/details/12748…

【软件设计师暴击考点】操作系统知识高频考点暴击系列【二】

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;元宇宙-秩沅 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 秩沅 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a;软件…

栈的应用——括号匹配、表达式求值、递归

目录 一、栈在括号匹配中的应用逻辑实现代码实现 二、栈在表达式求值中的应用手算实现代码实现 三、栈在递归中的应用逻辑实现代码实现 一、栈在括号匹配中的应用 括号匹配&#xff0c;顾名思义。若括号按照正确的格式嵌套&#xff0c;则可正确匹配&#xff0c;例如([])&#…

scratch lenet(12): LeNet-5输出层和损失函数的计算

文章目录 1. 目的2. 输出层结构2.1 Gaussian Connection2.2 Gaussian Connection 的 weight 可视化 3. Loss Function3.1 当前类别判断错误时&#xff0c;loss function 中的项&#xff08;基本项&#xff09;3.2 判断为其他类别时&#xff0c; loss function 中的项&#xff0…

Spring发展历程及其体系结构

⭐作者介绍&#xff1a;大二本科网络工程专业在读&#xff0c;持续学习Java&#xff0c;努力输出优质文章 ⭐作者主页&#xff1a;逐梦苍穹 ⭐所属专栏&#xff1a;Spring 目录 发展历程体系结构 发展历程 体系结构 Spring框架的体系结构的主要组成部分&#xff1a; 核心容器…

idea如何集成Tomcat

&#xff08;1&#xff09;、这里应该找Add Configuration点击这里&#xff1a;如果没有标志&#xff0c;点击Exit (2)、这里可以配置一个配置项&#xff1a; &#xff08;3&#xff09;、loacl是本地&#xff0c;那个是远程&#xff1a;这里我选择本地 &#xff08;4&#xff…

代码随想录算法训练营第四十二天 | 01背包理论基础,01背包理论基础(滚动数组),416. 分割等和子集

代码随想录算法训练营第四十二天 | 01背包理论基础&#xff0c;01背包理论基础&#xff08;滚动数组&#xff09;&#xff0c;416. 分割等和子集 1.1 01背包理论基础 01背包 回溯法&#xff1a;暴力的解法是o(2^n)指数级别的时间复杂度&#xff0c;需要动态规划的解法来进行优…

如果你曾经拥有python,那么现在你应该拥抱Julia吗?

看完本文&#xff0c;您就会有较成熟的想法。 Julia和Python的区别是什么&#xff1f;为什么Julia适合用于大规模计算和超级计算机模拟&#xff1f; 你一定听说过Julia和Python这两个编程语言。虽然它们都可以用于从简单的机器学习应用程序到巨大的超级计算机模拟的所有方面&am…

Gradio的Audio组件介绍

❤️觉得内容不错的话&#xff0c;欢迎点赞收藏加关注&#x1f60a;&#x1f60a;&#x1f60a;&#xff0c;后续会继续输入更多优质内容❤️ &#x1f449;有问题欢迎大家加关注私戳或者评论&#xff08;包括但不限于NLP算法相关&#xff0c;linux学习相关&#xff0c;读研读博…