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

Spring事件异步执行设计与实现

Spring事件异步执行设计与实现

背景

默认情况下,Spring的事件监听是同步执行的,也就是publishEvent方法来触发ApplicationListener执行的。当然了也可以配置成异步去执行,但是这是全局的,所有的事件都会变成异步执行了(需要自己配置一个ApplicationEventMulticaster并给它设置一个线程池)。

设计与实现

AsyncEvent.java

/*** 所有异步事件的基类*/
public abstract class AsyncEvent<T> extends ApplicationEvent {@Serialprivate static final long serialVersionUID = -3876435908556202255L;private final T payload;public AsyncEvent(T payload, Object source) {super(source);this.payload = payload;}public T getPayload() {return payload;}
}

AsyncEventListener.java

/*** 监听器, 将事件分发到线程池中执行*/
package com.wangtao.springboot3.event;import com.wangtao.springboot3.event.handler.AsyncEventHandler;
import com.wangtao.springboot3.executor.CatchExceptionThreadFactory;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.util.LambdaSafe;
import org.springframework.context.event.EventListener;
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
import org.springframework.core.task.TaskRejectedException;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;import java.util.List;/*** @author wangtao* Created at 2026-03-13*/
@Component
public class AsyncEventListener implements DisposableBean {private final ThreadPoolTaskExecutor taskExecutor;private final List<AsyncEventHandler<?>> asyncEventHandlerList;private boolean useDefaultTaskExecutor;public AsyncEventListener(@Qualifier("asyncEventTaskExecutor") ObjectProvider<ThreadPoolTaskExecutor> taskExecutorProvider,List<AsyncEventHandler<?>> asyncEventHandlerList) {this.taskExecutor = taskExecutorProvider.getIfAvailable(() -> {this.useDefaultTaskExecutor = true;return this.defaultTaskExecutor();});this.asyncEventHandlerList = asyncEventHandlerList;// 根据@Order或者Ordered接口排序AnnotationAwareOrderComparator.sort(this.asyncEventHandlerList);}@EventListenerpublic void onAsyncEvent(AsyncEvent<?> asyncEvent) {try {this.taskExecutor.execute(() -> dispatchAsyncEvent(asyncEvent));} catch (TaskRejectedException e) {// 任务提交失败, 做补偿}}@SuppressWarnings("unchecked")private void dispatchAsyncEvent(AsyncEvent<?> asyncEvent) {// 会根据实际的asyncEvent实例来判断交给哪一个handler执行LambdaSafe.callbacks(AsyncEventHandler.class, asyncEventHandlerList, asyncEvent).invoke(asyncEventHandler -> asyncEventHandler.handle(asyncEvent));}@Overridepublic void destroy()  {if (this.useDefaultTaskExecutor) {this.taskExecutor.destroy();}}private ThreadPoolTaskExecutor defaultTaskExecutor() {ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();taskExecutor.setCorePoolSize(4);taskExecutor.setMaxPoolSize(8);taskExecutor.setThreadFactory(new CatchExceptionThreadFactory("async-event"));taskExecutor.setQueueCapacity(1000);taskExecutor.setWaitForTasksToCompleteOnShutdown(true);taskExecutor.setAwaitTerminationSeconds(20);taskExecutor.initialize();return taskExecutor;}
}

AsyncEventHandler.java

/*** 真正执行事件的接口*/
public interface AsyncEventHandler<T extends AsyncEvent<?>> {void handle(T asyncEvent);
}

使用与测试

public class LikeAsyncEvent extends AsyncEvent<Integer> {@Serialprivate static final long serialVersionUID = 1761508846850771470L;public LikeAsyncEvent(Integer payload, Object source) {super(payload, source);}
}
public class CommentAsyncEvent extends AsyncEvent<String> {@Serialprivate static final long serialVersionUID = 1761508846850771470L;public CommentAsyncEvent(String payload, Object source) {super(payload, source);}
}
@Slf4j
@Component
public class LikeAsyncEventHandler implements AsyncEventHandler<LikeAsyncEvent> {@Overridepublic void handle(LikeAsyncEvent asyncEvent) {log.info("======handle likeAsyncEvent, data: {}", asyncEvent.getPayload());}
}
@Slf4j
@Component
public class CommentAsyncEventHandler implements AsyncEventHandler<CommentAsyncEvent> {@Overridepublic void handle(CommentAsyncEvent asyncEvent) {log.info("======handle commentAsyncEvent, data: {}", asyncEvent.getPayload());}
}
@Test
public void asyncEventTest() {applicationContext.publishEvent(new LikeAsyncEvent(1, this));
}
http://www.jsqmd.com/news/473371/

相关文章:

  • 身体炎症多如何调理?2026年慢性炎性衰老干预指南:热门抗衰手段多维度深度测评 - 资讯焦点
  • 二分搜索树
  • Dependency-Track实战:基于Docker与MySQL8的SBOM安全分析平台搭建
  • Qwen3-ASR-0.6B高并发测试:128并发2000倍吞吐实战
  • JQ8900-16P语音模块串口驱动移植与天空星STM32F407实战应用
  • 基于Vue3的Nano-Banana Studio前端控制台开发
  • 面试题|MySQL InnoDB索引不选择hash的原因
  • C 头文件
  • 紧急!MCP v3.6升级后Sampling调用流中断?2小时内恢复方案:5步回滚检查清单 + 4个兼容性补丁 + 1份经CNCF SIG-Observability认证的验证脚本
  • 面试题|MySQL InnoDB B+树内部节点为什么存储索引健值不存储数据行
  • go面经(1)
  • gte-base-zh部署SLA保障:99.9%可用性设计——双活Xinference节点方案
  • MVC 控制器
  • 紧急预警:PHP 8.3已废弃ReflectionProperty::setAccessible()!你的低代码表单动态赋值逻辑正在 silently 失效(附向后兼容热补丁)
  • 解锁yolov8全能力:借助快马平台ai助手玩转分割与姿态估计
  • C++20 auto 写法
  • 历史一轮复习大纲
  • DeepSeek-OCR开源模型教程:基于<|grounding|>提示词的空间感知调用
  • 突破Windows版本限制:MediaCreationTool.bat全场景介质创建应用指南
  • figmaCN插件全攻略:从安装到定制的设计师本地化解决方案
  • wpf canvas 移动 缩放
  • YOLO-V5目标检测实战:识别图片中物体位置,附完整代码示例
  • 【CVPR26-孙栩-北京大学】Conan:像侦探一样对多尺度视觉证据进行渐进式学习推理
  • 打破PDF笔记壁垒:Obsidian PDF Plus让文献管理效率提升300%的秘密
  • 2026 深度审计:ChatGPT Plus 国内充值封锁现状与“免密码”激活方案实测
  • translategemma-12b-it效果实测:技术文档扫描件翻译准确率惊人
  • Hotkey Detective:Windows热键冲突的智能诊断解决方案
  • Ostrakon-VL-8B MySQL数据可视化:将图片分析结果转化为商业洞察
  • 南北阁 Nanbeige 4.1-3B Streamlit定制:支持暗色模式与字体大小调节
  • LangGraph实战:AI从此‘过目不忘’——知识库+记忆宫殿实现持续学习,拒绝信息丢失!