Springboot异步事件配置和使用
Spring中提供了完整的事件处理机制,本身底层内置实现了一些事件和监听,同时支持开发者扩展自己的事件和监听实现。
一般这种基于事件的实现在项目实际开发中我们主要用来解耦,和做异步处理(默认是同步),提供应用的响应速度。
核心架构
先简要看一下,在Spring中要实现自定义事件监听需要涉及哪些接口类,这里忽略异步的引用、注解的实现,后面会说到。

基本实现步骤
- 自定义事件:一般继承自ApplicationEvent即可,注意里面要去定义和实现自己的事件方法,也就是具体这个事件要做什么事,一般就在事件类、或者基于事件类去实现即可。
- 事件发布:业务代码中注入ApplicationEventPublisher类,然后再具体业务方法中调用publishEvent方法,传入上面自定义的事件,以及自定义的必要参数等信息
- 实现事件监听:有了事件、也发布了,那必须有对应的监听来调用具体的事件,一般实现ApplicationListener泛型传入自己的事件类型即可
注意事项
- 异常和事物:默认情况下事件的发布、监听处理都是和当前业务线程绑定到一起的,也就是在同一个线程中操作事件任务。因此无论是事件发布时导致异常,或者是具体事件任务实现的方法异常,都会导致当前业务异常;相应的如果当前业务有事物,那么异常了也会回滚。
- 事件类型:首先一定要自定义自己的事件,其次在监听的时候也是监听自己的事件,而不是监听基类或者接口然后去判断,这样反而失去了基于事件监听编程灵活性,同时也违法开闭原则,并不利于后期扩展。具体事件中可以定义其他一些额外的参数,这样方便在具体方法中传参使用
- 事件顺序:一次可以发布多个事件,无论是同一个还是不同的,执行顺序默认也是按照发布顺序。
场景应用
这里以订单完成和推送给平台订单相关数据为业务模型来举例说明。Spring4.2之后提供了注解来实现事件监听,非常的方便,这里我们使用注解的方式实现监听即可。
- 缩略的业务类:包含事件的发布
@Resource
private ApplicationEventPublisher publisher;
public void completeTrade(TradeOrder trade){
tradeMapper.modifyStatus(trade);
publisher.publishEvent(new TradeStatusEvent(this,new TradeStatusEvent.Params(trade,"完成订单")));
}
- 具体事件的定义:继承自ApplicationEvent
public class TradeStatusEvent extends ApplicationEvent {
private static final Logger logger = LoggerFactory.getLogger(TradeStatusEvent.class);
private Params params;
public Params getParams(){
return this.params;
}
public TradeStatusEvent(Object source,Params param) {
super(source);
this.param = param;
}
public void send(){
try{
HttpUtils.send("xx.oo", PlatformBean.Builder().note(this.params.note)..build());
} catch(Exception e){
logger.error("TradeStatusEvent处理异常:",e);
}
}
public static class Params {
private TradeOrder trade;
private String note;
//get、set 定义其他参数等
}
}
- 监听实现:使用注解,注意这里我使用了 事务监听注解 ,按照具体业务场景可以选择具体的注解,比如最常用的@EventListener。因为我这里的诉求是当前事物提交完成之后再去推送消息,而且实际情况是启用了异步监听来实现,同时有的人在监听的方法中可能还执行了回查,也就是去查询业务中提交的数据,那如果这里不标记为事物提交之后执行,在异步情况下无法获取到数据
@Component
public class TradeStatusEventListener {
@TransactionalEventListener(phase= TransactionPhase.AFTER_COMMIT, fallbackExecution=true)
void handlerAfterComplete(TradeStatusEvent event) {
event.send();
}
}
异步实现
所谓异步实现,一般是指异步监听,将主体业务逻辑和消息监听任务放到不同的线程去执行,提高业务的响应速度。
Springboot中我们有多个办法来实现异步监听执行,最简单、最直接的就和异步方法实现一模一样,只需在监听方法上加上@Async注解(前提是启用了异步执行)
- 第一种办法:Configuration配置类中加上注解@EnableAsync,启用Spring的异步方法执行能力。然后在监听方法上加上@Async注解,标明此方法是异步执行。Over就这样就行了【我们没有配置异步线程对不对?那是会直接new Thread()来执行异步任务吗,当然不是,而是Spring默认提供并初始化了一个专门用来执行异步任务的线程池ThreadPoolTaskExecutor,会接管所有的异步任务在同一个线程池中执行。也支持定制化处理,后续我们会说到】
@Configuration
@EnableAsync
public class AppConfig{}
//````
@Component
public class TradeStatusEventListener {
@Async
@TransactionalEventListener(phase= TransactionPhase.AFTER_COMMIT, fallbackExecution=true)
void handlerAfterComplete(TradeStatusEvent event) {
event.send();
}
}
- 第二种办法:如果说不想全局开启异步,只是想给事件监听的代码实现异步任务呢?那最简单就是直接在监听哪里new Thread().start(),不受控、不优雅,但是业务场景简单,访问量小的情况下也不是不可以。那要规范一点呢,就是自己创建一个线程池,比如ExecutorService executorService = Executors.newCachedThreadPool();然后在event.send哪里使用executorService.execute(..)执行即可。
- 第三种办法:优雅点实现,创建SimpleApplicationEventMulticaster的Bean,然后创建一个线程池给塞进去,注意需要把自定义实现注入到Spring容器中。其他代码不用做任何修改,就像同步逻辑一样,在事件发布的时候广播会使用multicastEvent调用taskExecutor获取一个线程去执行监听任务
@Configuration
public class AppConfig{
@Bean
public SimpleApplicationEventMulticaster simpleApplicationEventMulticaster(){
SimpleApplicationEventMulticaster mu = new SimpleApplicationEventMulticaster();
//这里我使用spring提供的任务构造器创建了一个立即执行的有界队列任务线程池
Executor taskExecutor = new TaskExecutorBuilder().corePoolSize(8).maxPoolSize(200).queueCapacity(20).threadNamePrefix("trade-send-").build();
mu.setTaskExecutor(taskExecutor);
//设置异常处理
mu.setErrorHandler((t)->{
//logger.error("==========调用平台发送消息方法失败,",t);
});
return mu;
}
}
框架原理
- 为什么异步监听只需要@EnableAsync、以及在方法上加上@Async就可以了呢?
当我们使用Springboot,引入starter时会自动引入spring-boot-autoconfigure,此包里面实现了很多自动配置的功能(约定大于配置)名字都是xxxAutoConfiguration,比如我们这里要说的就是TaskExecutionAutoConfiguration,容器启动的时候就会加载和创建默认的任务线程池,可以通过spring.task.execution开头属性来配置。需要注意的是,无论是否加入@EnableAsync注解TaskExecutionAutoConfiguration都会初始化一个默认的线程池,因为这个是全局的。

@EnableAsync的作用是在容器启动的时候,告诉Spring我可要支持异步处理任务了,你看着办。Spring所好的朋友,我给你准备了一个专门搞事的拦截器。

当我们加入了注解,Spring会将按照配置将准备工作全部做完,从而做到开箱即用,直接一步到位。
总结
- Spring事件模型的四个核心:事件源也就是业务方、事件、广播器、监听器
- 事件机制支持同步、异步,按需调整和使用。使用异步监听时,推荐使用线程池管理线程,高效、稳定而且易于维护。
- 使用Springboot时通过注解的方式监听、启用异步尽享丝滑。实际原理核心就是观察者模式。
Springboot异步事件配置和使用的更多相关文章
- SpringBoot系列——事件发布与监听
前言 日常开发中,我们经常会碰到这样的业务场景:用户注册,注册成功后需要发送邮箱.短信提示用户,通常我们都是这样写: /** * 用户注册 */ @GetMapping("/userRegi ...
- SpringBoot + Log4j2使用配置 (转)
前言 后台程序开发及上线时,一般都会用到Log信息打印及Log日志记录,开发时通过Log信息打印可以快速的定位问题所在,帮助我们快捷开发.程序上线后如遇到Bug或错误,此时则需要日志记录来查找发现问题 ...
- 【转】第8章 前摄器(Proactor):用于为异步事件多路分离和分派处理器的对象行为模式
目录: Reactor(反应堆)和Proactor(前摄器) <I/O模型之三:两种高性能 I/O 设计模式 Reactor 和 Proactor> <[转]第8章 前摄器(Proa ...
- 01-项目简介Springboot简介入门配置项目准备
总体课程主要分为4个阶段课程: ------------------------课程介绍------------------------ 01-项目简介Springboot简介入门配置项目准备02-M ...
- spring中的异步事件
这里讲解一下Spring对异步事件机制的支持,实现方式有两种: 1.全局异步 即只要是触发事件都是以异步执行,具体配置(spring-config-register.xml)如下: Java代码 ...
- 新手也能看懂的 SpringBoot 异步编程指南
本文已经收录自 springboot-guide : https://github.com/Snailclimb/springboot-guide (Spring Boot 核心知识点整理. 基于 S ...
- springboot异步线程(二)
前言 本篇文章针对上篇文章springboot异步线程,有一位大佬在评论中提出第一点是错误的,当时看到了这个问题,最近刚好有空,针对第一点的问题去搜索了不少的文章: 问题 我在文章中第一点去验证:Sc ...
- SpringBoot异步编程
异步调用:当我们执行一个方法时,假如这个方法中有多个耗时的任务需要同时去做,而且又不着急等待这个结果时可以让客户端立即返回然后,后台慢慢去计算任务.当然你也可以选择等这些任务都执行完了,再返回给客户端 ...
- 关于SpringBoot的自动配置和启动过程
一.简介 Spring Boot简化了Spring应用的开发,采用约定大于配置的思想,去繁从简,很方便就能构建一个独立的.产品级别的应用. 1.传统J2EE开发的缺点 开发笨重.配置繁多复杂.开发效率 ...
- SpringBoot 异步 定时任务 邮件
springboot异步 一: 在 MyConfiguration.java 中开启注解 @Configuration//指明当前类是一个配置类:就是来替代之前的Spring配置文件@EnableAs ...
随机推荐
- opencv-python报错:fatal error: jpeglib.h: No such file or directory
参考: https://blog.csdn.net/yang_xuexi/article/details/123303777 https://blog.csdn.net/u010835747/arti ...
- Java和LWJGL的关于OpenAL的文章
一.OpenAL的原理和基本概念: 1.1 OpenAL的架构 OpenAL的架构同样基于三个核心组件:Context(上下文).Source(声源)和Buffer(缓冲区).Context代表了音频 ...
- Linux与windows共享文件的神器:samba
一.什么是samba? 搭建Samba服务器是为了实现Linux共享目录之后,在Windows可以直接访问该共享目录. 现在介绍如何在ubuntu 16.04系统中搭建Samba服务. 二 .samb ...
- zabbix snmp OID 列表
系统参数(1.3.6.1.2.1.1) OID 描述 备注 请求方式 .1.3.6.1.2.1.1.1.0 获取系统基本信息 SysDesc GET .1.3.6.1.2.1.1.3.0 监控时间 s ...
- Oracle数据库安装与还原
安装Oracle 11g数据库 安装数据库参考这位大佬的文章:(135条消息) Oracle 11g版本下载及安装超详细教程图解_oracle11g下载_田夜的博客-CSDN博客 非常详细 利用dmp ...
- .NET Core3.1 跨域 Cors 找不到 “Access-Control-Allow-Origin”
今天在做项目的时候遇到了调用WebAPI跨域的问题 No 'Access-Control-Allow-Origin' header is present on the requested resour ...
- CMake构建学习笔记8-OpenSceneGraph库的构建
1. 概论 在连续构建了zlib.libpng.libjpeg.libtiff.giflib以及freetype这几个库之后,接下来我们就要来一个大的,构建OpenSceneGraph这样大型库.Op ...
- AI产品经理的探索:技能、机遇与未来展望
Ai时代的产品经理 随着人工智能(AI)的飞速发展,AI已经从一个前沿技术概念逐步演变为驱动各行业创新的核心力量.从智能助手到自动驾驶,从个性化推荐系统到图像识别,AI正在以不可思议的速度改变着我们的 ...
- Coze插件发布!PDF转Markdown功能便捷集成,打造你的专属智能体
近日,TextIn开发的PDF转Markdown插件正式上架Coze平台. 在扣子搜索"pdf转markdown",或在Coze平台搜索"pdf2markdown&quo ...
- CIIS 2023 丨聚焦文档图像处理前沿领域,合合信息 AI 助力图像处理与内容安全保障
近日,2023第十二届中国智能产业高峰论坛(CIIS 2023)在江西南昌顺利举行.大会由中国人工智能学会.江西省科学技术厅.南昌市人民政府主办,南昌市科学技术局.中国工程科技发展战略江西研究院承办. ...