事件发布与监听

@EventListener

在Spring框架下,默认被@EventListener的方法是同步的,即事件发布线程会阻塞等待所有监听器方法执行完毕后再继续执行;

而且如果发布事件的方法处在事务中,那么监听器也默认和事件发布处于同一事务中;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Component;@Component
public class MyEventPublisher {@Autowiredprivate ApplicationEventPublisher applicationEventPublisher;public void publishEvent() {MyEvent event = new MyEvent(this);// 发布事件applicationEventPublisher.publishEvent(event);}
}
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;@Component
public class MyEventListener {@EventListenerpublic void handleMyEvent(MyEvent event) {// 这个方法是同步执行的,会阻塞事件发布线程System.out.println("Handling event: " + event);}
}

 

当然,我们可以通过@Async注解使事件监听器方法异步执行,而且也顺便解决了在同一事务的问题,即事件发布和事件监听处在不同事务中

import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;@Component
public class MyAsyncEventListener {@Async@EventListenerpublic void handleMyEvent(MyEvent event) {// 这个方法是异步执行的,不会阻塞事件发布线程System.out.println("Handling event asynchronously: " + event);}
}

 

 

@TransactionalEventListener

现在有一个新的需求:

  1、创建一个用户

  2、用户创建成功后,发送邮件给用户

 

可能你会很轻易的想到如下代码逻辑:

@Transactional
public User createUser(User user) {User newUser = userRepository.save(user);emailService.sendEmail(user.getEmail());return newUser;
}

但仔细想想,上述代码存在两个问题:

  1、如果邮件发送失败,事务发生回滚,从而导致用户创建失败

  2、邮件发送成功后,事务提交失败,导致用户收到了邮件,但账号创建失败

 

可能你又会想到加入事件监听器来完成解耦

/**
* 事件发布
*/
@Transactional
public Customer createCustomer(User user) {User newUser = userRepository.save(user);final UserCreatedEvent event = new UserCreatedEvent(newUser);applicationEventPublisher.publishEvent(event);return newUser;
}/**
* 事件监听
*/
@Component
public class UserCreatedEventListener {private final EmailService emailService;public UserCreatedEventListener(EmailService emailService) {this.emailService = emailService;}@EventListenerpublic void processUserCreatedEvent(UserCreatedEvent event) {emailService.sendEmail(event.getUser().getEmail());}
}

但是@EventListener 是和事件发布处于同一事务中, 其结果是和之前的代码一样;

 

如果加上@Async注解,也可能会出现邮件发送成功但用户创建失败的情况

 

如果不加事务会怎么样呢?如果事件能发布,则说明用户创建成功,那么对于邮件是否发送成功,其实对于业务来说以及不重要了,好像问题真的已经被解决!有那么一丢丢尴尬

 

但我还是想说另外一种解决方案(适用于有事务的情况):@TransactionalEventListener

参数phase介绍:BEFORE_COMMIT:在事务提交前执行AFTER_COMMIT:在事务提交后执行AFTER_ROLLBACK:在事务回滚后执行AFTER_COMPLETION:在事务完成时执行,这里的完成是指无论事务是成功提交还是事务回滚了参数fallbackExecution介绍:如果该事件不在事务中,且值为flase,事件将不会被处理,直接被丢弃如果该事件不在事务中,且值为true,则直接执行目标方法,效果和@EventListener一样@EventListener在底层上还是同一个事务,且是同步的,即事件监听器会阻塞事件发布线程,直到监听器方法执行完毕;当然也可以使用@Async注解使标记方法异步执行

也就是说该注解可以实现:事件发布线程事务提交之后再去执行目标方法,也就真正做到用户创建和邮件发布解耦

 

参考文章

【1】@TransactionalEventListener注解的使用场景

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

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

相关文章

Redis+Docker集群部署

机器故障了怎么办? Redis 是内存数据库,我们知道可以通过持久化机制,保存快照或者保存记录日志的方式,将数据持久化到磁盘。但是,如果机器故障了或磁盘坏了,数据就不就全没了吗?这种情况应该怎么办呢?别担心,考虑主从模式。 主从模式 给主节点 Master 配置一个从节点 …

【T20天正电气V10.0软件下载与安装教程】

1、安装包 扫描下方二维码关注「软知社」,后台回复【024】三位数字即可免费获取分享链接,无广告拒绝套路; 2、安装教程双击T20天正电气V10.0安装包,弹窗安装对话框选择我接收,点击下一步选择安装位置,点击下一步点击下一步等待安装进度完成安装完成,点击完成按钮点击下…

windows底层激活破解一步到位,TSforge也太暴力了!

windows底层激活破解一步到位,TSforge也太暴力了! windows底层激活破解一步到位,TSforge也太暴力了! 微软系统一直是需要收费的,也是电脑用户们经常遇到的问题,市面上也有很多工具, 但是今天的工具是最新的且**呼声最高、最彻底的**,需要的话赶紧保存下来,实际使用只需…

No.23 CSS--定位

一、定义position属性指定了元素的定位类型。其中,绝对定位和固定定位会脱离文档流. 设置定位之后:可以使用四个方向值进行调整位置:Ieft、top、right、bottom.二、相对定位<head><meta charset="UTF-8"><meta name="viewport" content=&q…

机器人保养指南周期性检修

机器人保养指南——那智不二越机器人日常维护、专业维修与周期性检修在进行那智不二越机器人的日常检查、维修、部件更换或任何其他相关作业时,首要且至关重要的一步是确保已切断电源,只有在完全断电的情况下,方可安全地进行后续操作。此外,还应在一次电源等关键位置设置明…

OERV兴趣探索:模拟器移植

最近看了很多开源项目,主要都集中在模拟器方面,我指的是游戏模拟器比如GameBoy或者PlayStation这一类。现在想玩这系列的游戏可以在手机或者电脑下载相应的模拟器,并且获取对应的ROM文件,不过也有一些模拟器是可以运行在Linux上面的,为了进一步探索,我选择了相对较小的项…

HTTP协议与RESTful API实战手册(二):用披萨店故事说透API设计奥秘

title: HTTP协议与RESTful API实战手册(二):用披萨店故事说透API设计奥秘 🍕 date: 2025/2/27 updated: 2025/2/27 author: cmdragon excerpt: 📦 本系列第二篇通过披萨店创业的完整案例,手把手教你: 用外卖订单理解HTTP协议细节 5个RESTful设计常见误区与修正方案 …

全局注册svg批量自动引入,动态修改svg以及样式配置问题

1.安装依赖npm i vite-plugin-svg-icons2.文件存放svg 3.全局组件svg-icon(直接放到全局组件目录下)<template><svg class="svg-icon"><use :xlink:href="`#icon-${props.name}`" class="mySVG":style="stroke: + props.…

msyql中单表语句

二、聚合函数 (1)max 最小值 select max(math) from student (2)min 最大值 select min(math) from student (3)sum 总数 select sum(math) from student (4)avg平均数 select avg(math) from student (5)count 统计个数 select count(math) from stu…

Java SpringBoot实现简易扫码登录流程 附项目代码

SpringBoot实现简易扫码登录流程,附项目代码先总结流程:移动端请求扫码登录,服务端生成二维码并缓存二维码ID和状态,将二维码的Base64格式返回给前端展示; PC端页面轮询检查二维码状态; 手机扫码后调用扫码接口,携带移动端的Token和二维码ID请求服务端,服务端根据扫码的…

Salesforce宣布2025年不招工程师,技术岗位真的会消失吗?

Salesforce CEO Marc Benioff 最近放出了一条让科技圈热议的消息:2025年,Salesforce将不再招聘新的软件工程师。作为全球最大的CRM软件提供商之一,这一决定引发了许多人对AI对就业市场影响的思考。 AI改变工作模式,工程师岗位需求减少 Marc Benioff 在采访中透露,2024年,…

mysql查询语句

一、查询语句 1、select查询一个表中的所有数据 格式: select * from 表名 ; 案例: select * from student ;2、查询部分字段信息数据 格式: select 字段1,字段2 from 表名; 案例: select name,math from student;3、查询字段可以用as 取别名 格式: select 字…