前言
日常开发中,我们经常会碰到这样的业务场景:用户注册,注册成功后需要发送邮箱、短信提示用户,通常我们都是这样写:
/**
* 用户注册
*/
@GetMapping("/userRegister")
public String userRegister(UserVo userVo) {
//校验参数 //存库 //发送邮件 //发送短信 //API返回结果
return "操作成功!";
}
可以发现,用户注册与信息推送强耦合,用户注册其实到存库成功,就已经算是完成了,后面的信息推送都是额外的操作,甚至信息推送失败报错,还会影响API接口的结果,如果在同一事务,报错信息不捕获,还会导致事务回滚,存库失败。
官方文档相关介绍:https://docs.spring.io/spring-boot/docs/2.1.0.RELEASE/reference/htmlsingle/#boot-features-application-events-and-listeners
本文记录springboot使用@EventListener监听事件、ApplicationEventPublisher.publishEvent发布事件实现业务解耦。
代码
项目结构
默认情况下,事件的发布和监听操作是同步执行的,我们先配置一下async,优雅多线程异步任务,详情请戳:SpringBoot系列——@Async优雅的异步调用
启动类添加@EnableAsync注解
/**
* 异步任务线程池的配置
*/
@Configuration
public class AsyncConfig { private static final int MAX_POOL_SIZE = 50; private static final int CORE_POOL_SIZE = 20; @Bean("asyncTaskExecutor")
public AsyncTaskExecutor asyncTaskExecutor() {
ThreadPoolTaskExecutor asyncTaskExecutor = new ThreadPoolTaskExecutor();
asyncTaskExecutor.setMaxPoolSize(MAX_POOL_SIZE);
asyncTaskExecutor.setCorePoolSize(CORE_POOL_SIZE);
asyncTaskExecutor.setThreadNamePrefix("async-task-");
asyncTaskExecutor.initialize();
return asyncTaskExecutor;
}
}
多数情况下的业务操作都会涉及数据库事务,可以使用@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)注解开启事务监听,确保数据入库后再进行异步任务操作。
定义事件源
先定义两个事件源,继承ApplicationEvent
/**
* 用户Vo
*/
@Data
public class UserVo { private Integer id; private String username;
} /**
* 用户事件源
*/
@Getter
@Setter
public class UserEventSource extends ApplicationEvent {
private UserVo userVo; UserEventSource(UserVo userVo) {
super(userVo);
this.userVo = userVo;
}
}
/**
* 业务工单Vo
*/
@Data
public class WorkOrderVo { private Integer id; private String WorkOrderName;
} /**
* 业务工单事件源
*/
@Getter
@Setter
public class WorkOrderEventSource extends ApplicationEvent {
private cn.huanzi.qch.springbooteventsandlisteners.pojo.WorkOrderVo WorkOrderVo; WorkOrderEventSource(WorkOrderVo WorkOrderVo) {
super(WorkOrderVo);
this.WorkOrderVo = WorkOrderVo;
}
}
监听事件
监听用户注册事件、监听业务工单发起事件
/**
* 事件监听
*/
@Slf4j
@Component
public class EventListenerList { /**
* 用户注册事件监听
*/
@Async("asyncTaskExecutor")
@EventListener
@Order(1)//一个事件多个事监听,使用@order值越小,执行顺序优先
public void userRegisterListener(UserEventSource eventSourceEvent){
log.info("用户注册事件监听1:"+eventSourceEvent.getUserVo()); //开展其他业务,例如发送邮件、短信等
}
/**
* 用户注册事件监听
*/
@Async("asyncTaskExecutor")
@EventListener
@Order(2)//一个事件多个事监听,使用@order值越小,执行顺序优先
public void userRegisterListener2(UserEventSource eventSourceEvent){
log.info("用户注册事件监听2:"+eventSourceEvent.getUserVo()); //开展其他业务,例如发送邮件、短信等
} /**
* 业务工单发起事件监听
*/
@Async("asyncTaskExecutor")
@EventListener
public void workOrderStartListener(WorkOrderEventSource eventSourceEvent){
log.info("业务工单发起事件:"+eventSourceEvent.getWorkOrderVo()); //开展其他业务,例如发送邮件、短信等
}
}
发布事件
创建一个controller,新增两个测试接口
/**
* 事件发布
*/
@Slf4j
@RestController
@RequestMapping("/eventPublish/")
public class EventPublish { @Autowired
private ApplicationEventPublisher applicationEventPublisher; /**
* 用户注册
*/
@GetMapping("userRegister")
public String userRegister(UserVo userVo) {
log.info("用户注册!"); //发布 用户注册事件
applicationEventPublisher.publishEvent(new UserEventSource(userVo)); return "操作成功!";
} /**
* 业务工单发起
*/
@GetMapping("workOrderStart")
public String workOrderStart(WorkOrderVo workOrderVo) {
log.info("业务工单发起!"); //发布 业务工单发起事件
applicationEventPublisher.publishEvent(new WorkOrderEventSource(workOrderVo)); return "操作成功!";
}
}
效果
用户注册
http://localhost:10010/eventPublish/userRegister?id=1&username=张三
API返回
后台异步任务执行
工单发起
http://localhost:10010/eventPublish/workOrderStart?id=1&workOrderName=设备出入申请单
API返回
后台异步任务执行
后记
springboot使用事件发布与监听就暂时记录到这,后续再进行补充。
代码开源
代码已经开源、托管到我的GitHub、码云:
GitHub:https://github.com/huanzi-qch/springBoot
码云:https://gitee.com/huanzi-qch/springBoot
SpringBoot系列——事件发布与监听的更多相关文章
-
Spring知识点回顾(07)事件发布和监听
Spring知识点回顾(07)事件发布和监听 1.DemoEvent extends ApplicationEvent { public DemoEvent(Object source, String ...
-
spring 自定义事件发布及监听(简单实例)
前言: Spring的AppilcaitionContext能够发布事件和注册相对应的事件监听器,因此,它有一套完整的事件发布和监听机制. 流程分析: 在一个完整的事件体系中,除了事件和监听器以外,还 ...
-
Spring事件发布与监听机制
我是陈皮,一个在互联网 Coding 的 ITer,微信搜索「陈皮的JavaLib」第一时间阅读最新文章,回复[资料],即可获得我精心整理的技术资料,电子书籍,一线大厂面试资料和优秀简历模板. 目录 ...
-
SpringBoot | 第三十二章:事件的发布和监听
前言 今天去官网查看spring boot资料时,在特性中看见了系统的事件及监听章节.想想,spring的事件应该是在3.x版本就发布的功能了,并越来越完善,其为bean和bean之间的消息通信提供了 ...
-
关于JAVA中事件分发和监听机制实现的代码实例-绝对原创实用
http://blog.csdn.net/5iasp/article/details/37054171 文章标题:关于JAVA中事件分发和监听机制实现的代码实例 文章地址: http://blog.c ...
-
JavaEE开发之Spring中的事件发送与监听以及使用@Profile进行环境切换
本篇博客我们就来聊一下Spring框架中的观察者模式的应用,即事件的发送与监听机制.之前我们已经剖析过观察者模式的具体实现,以及使用Swift3.0自定义过通知机制.所以本篇博客对于事件发送与监听的底 ...
-
Pox启动及事件产生、监听分析
./pox/pox.py , Pox 实例化core=pox.core.initialize(),即为实例化POXCore类(该类是所有组件的交接点,提供组件注册功能),监听cor ...
-
apiCloud事件发送与监听
apiCloud事件发送与监听 1.sendEvent 将任意一个自定义事件广播出去,该事件可在任意页面通过 addEventListener 监听收到. sendEvent({params}) 2. ...
-
springboot13 发布和监听事件
spring中的事件驱动模型Event(也叫发布订阅模式),是观察者模式的一个典型的应用 好处:业务解耦,在不影响原来业务逻辑的情况下,加入其它业务 场景: app上线后已实现用户注册功能,现需要在用 ...
随机推荐
-
“.Net 社区虚拟大会”(dotnetConf) 2016 Day 1 Keynote: Scott Hunter
“.Net 社区虚拟大会”(dotnetConf) 2016 今天凌晨在Channel9 上召开,在Scott Hunter的30分钟的 Keynote上没有特别的亮点,所讲内容都是 微软“.Net社 ...
-
iOS面试题
一个区分度很大的面试题 考察一个面试者基础咋样,基本上问一个 @property 就够了: @property 后面可以有哪些修饰符? 线程安全的: atomic,nonatomic 访问权限的 re ...
-
MontageJS:构建现代 Web App 的 HTML5 框架
MontageJS 可以帮助您构建高可扩展性和可维护性的 HTML5 应用.有了 MontageJS,开发人员可以创建可重用的用户界面组件和模块,组件和控制器之间的绑定属性,并且同步 DOM 查询和更 ...
-
Inside the c++ object module 阅读摘要
这本书是 Stanley B. Lippman于1996年所写,而最早的c++标准是 ISO/IEC 14882:1998[18],即C++98. Chapter 1: Object Lessons ...
-
Effective C++ -----条款15:在资源管理类中提供对原始资源的访问
APIs往往要求访问原始资源(raw resources),所以每一个RAII class应该提供一个“取得其所管理之资源”的办法. 对原始资源的访问可能经由显示转换(.get()成员函数或者指针取值 ...
-
通过iphone蓝牙与经过苹果MFI授权认证的硬件通讯,传输图片(转)
http://blog.csdn.net/hwj2012/article/details/7883711 相关: http://blog.csdn.net/xufeidll/article/detai ...
-
OpenCV之响应鼠标(三):响应鼠标信息
转自:http://blog.csdn.net/haihong84/article/details/6599838 程序代碼如下: #include <cv.h>#include < ...
-
Windows下Nginx的启动、停止等命令(转)
Windows下Nginx的启动.停止等命令 在Windows下使用Nginx,我们需要掌握一些基本的操作命令,比如:启动.停止Nginx服务,重新载入Nginx等,下面我就进行一些简单的介绍.1.启 ...
-
String.PadLeft - 格式对齐
语法:public string PadLeft( int totalWidth, char paddingChar ) 概述,实现的效果是右对齐,返回一个总长度为 totalWidth,如果实际长度 ...
-
UESTC_基爷与加法等式 2015 UESTC Training for Search Algorithm &; String<;Problem C>;
C - 基爷与加法等式 Time Limit: 3000/1000MS (Java/Others) Memory Limit: 65535/65535KB (Java/Others) Subm ...