news 2026/3/5 17:26:51

Spring监听器(ApplicationEvent):比MQ更轻的异步神器!

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Spring监听器(ApplicationEvent):比MQ更轻的异步神器!

“顾客挤爆柜台时,优秀的店长不会催促咖啡师加速,而是启动一套科学的协作机制—— 就像Spring事件驱动,用发布-订阅模式让系统像顶级咖啡团队般优雅应对洪峰流量”

01

咖啡店里的监听器:3位灵魂角色

真实战场还原(每秒1000订单的咖啡店):

publicclassOrderEventextendsApplicationEvent{ // final修饰的订单ID:就像咖啡师绝不涂改的订单小票 privatefinal String orderId; // 创建时间:记录订单诞生时刻(线程安全不可变) privatefinal LocalDateTime createTime = LocalDateTime.now(); // 无setter:防止多线程并发篡改订单 }
@Service publicclassOrderService{ // 店长的麦克风(构造器注入更优雅) privatefinal ApplicationEventPublisher eventPublisher; publicvoidcreateOrder(Order order){ // 核心业务:生成订单(咖啡店接单) eventPublisher.publishEvent(new OrderEvent(this, order.getId())); // 📢 广播订单 } }
@Component publicclassCoffeeMakerListener{ @EventListener @Order(1) // 优先级:先做咖啡再推荐甜点 publicvoidmakeCoffee(OrderEvent event){ // 专注做咖啡,不关心谁结账 log.info("咖啡师:开始制作订单{}的拿铁...", event.getOrderId()); } }
  1. 事件定义:咖啡店的「订单小票」

  2. 事件发布:店长的「广播系统」

  3. 事件监听:咖啡团队的「技能响应」

02

扛住亿级流量的3把利器

场景1:冷启动缓存预加载(防雪崩)

@Component publicclassCachePreloader{ // 在Spring容器"开店准备完成"时触发 @EventListener(ContextRefreshedEvent.class) publicvoidinitCache() { // 异步加载省时30%(实测数据) CompletableFuture.runAsync(() -> { provinceService.loadProvincesToCache(); productService.preloadHotProducts(); }); } }

场景2:事务成功后的缓存清理(保一致性)

// 只在数据库提交成功后执行(避免脏清理) @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT) publicvoidcleanCache(OrderUpdateEvent event){ // 异步清理:不阻塞结账队伍 redisTemplate.executeAsync(new RedisCallback<>() { @Override public Void doInRedis(RedisConnection connection){ connection.del(("order:" + event.getId()).getBytes()); returnnull; } }); }

场景3:无侵入式功能扩展

改造前(臃肿的收银台):

publicvoidpay(){ paymentService.pay(); // 核心支付 auditService.log(); // 审计代码入侵 riskService.check(); // 风控代码耦合 marketingService.addPoints(); // 新增需求污染核心 }

事件驱动改造后:

// 纯净支付核心(专注收钱) publicvoidpay(Long orderId){ paymentService.process(orderId); eventPublisher.publishEvent(new PaymentSuccessEvent(orderId)); // 📢 广播支付成功 } // 新增积分模块(无需修改支付代码) @Component publicclassPointListener{ @EventListener publicvoidaddPoints(PaymentSuccessEvent event){ // 积分服务独立演进 pointService.award(event.getOrderId(), 100); } }

03

血泪教训:3个深夜加班事故

事故1:多线程篡改事件(订单混乱)

// 错误!事件必须是只读的 @EventListener publicvoidhandle(OrderEvent event){ event.setStatus("MODIFIED"); // ⚠️ 多线程并发修改引发订单错乱 }

正确做法: 事件类设计为final字段 + 无setter

事故2:异步事件丢失(顾客投诉)

@SpringBootApplication @EnableAsync// 必须显式开启异步 publicclassApplication{ @Bean("eventExecutor") public Executor taskExecutor(){ // 关键参数:拒绝策略用CallerRunsPolicy(避免丢单) ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); return executor; } } // 指定线程池执行 @Async("eventExecutor") @EventListener publicvoidasyncHandle(OrderEvent event){...}

事故3:事件循环调用(咖啡师卡死)

// 错误:在事件处理中发布新事件 @EventListener publicvoidhandleA(EventA a){ publisher.publishEvent(new EventB()); } @EventListener publicvoidhandleB(EventB b){ publisher.publishEvent(new EventA()); // ♻️ 死循环! }

04

关键抉择:监听器 vs MQ 架构对垒

维度

Spring监听器

MQ消息队列

适用场景

单机事务协作 ✅

跨服务通信 ✅

可靠性

进程宕机事件消失 ❌

持久化/重试 ✅

吞吐量

内存级传输,10w+/s 🚀

受网络限制,1w/s ⚠️

开发效率

免搭建MQ,注解即用 ✅

需部署中间件 ❌

数据一致性

本地事务保障 ✅

需分布式事务 ⚠️

黄金决策树:

同JVM事务操作 → Spring监听器(开发效率王炸)

跨服务最终一致 → RocketMQ(可靠性担当)

05

性能调优:监听器的涡轮增压

异步喷射:

@Async// 方法级异步(线程池加速) @EventListener publicvoidasyncProcess(LogEvent event){...}

条件过滤(减少无效处理):

// 只处理VIP客户的订单 @EventListener(condition = "#event.user.level == 'VIP'") publicvoidhandleVipOrder(OrderEvent event){...}

批量处理(Spring 4.2+特性):

// 一次性处理整批订单(提升数据库IO效率) @EventListener publicvoidbatchProcess(List<OrderEvent> events){ orderDao.batchInsert(events.stream().map(OrderConverter::toEntity).toList()); }

06

最佳实践:5条生存法则

1、单一职责原则

一个监听器只做一件事:如 PaymentListener 只处理支付, CouponListener 只发券

2、事件轻量化

禁止在事件中携带 HttpSession 等重型对象(建议只传ID)

3、异常隔离舱

异步事件必须独立捕获异常:

@Async @EventListener publicvoidhandle(Event event){ try { businessLogic(); } catch (Exception e) { // 记录日志 + 告警(防止雪崩) log.error("事件处理失败: {}", event, e); alarmManager.notify(e); } }

4、版本兼容设计

事件类预留版本字段:

publicclassOrderEvent{ privatefinal String version = "1.0"; // 未来可扩展 }
// 监控处理时长/失败率/QPS @Around("@annotation(org.springframework.context.event.EventListener)") public Object monitor(ProceedingJoinPoint pjp){ Timer.Sample sample = Timer.start(); try { return pjp.proceed(); } finally { sample.stop(Metrics.timer("event.process.time")); } }

5、监控三件套

优秀架构的本质不是预测所有需求,而是拥抱变化。

通过Spring事件监听器,我们将系统拆解为可插拔的乐高模块:

  • 新增功能时 → 添加监听器(无需修改核心代码)

  • 流量暴增时 → 开启异步(无需重构架构)

这恰如经营咖啡店的真谛:

“不是雇佣更快的咖啡师,而是设计永不拥堵的协作机制”

程序员彩蛋:

下回当你为需求变更焦头烂额时,不妨问问自己:

“我的代码,像一家应对自如的咖啡店吗?”

附录:性能压测数据(阿里云ECS 8核16G)

模式

吞吐量

平均延迟

CPU占用

同步监听

12,000/s

15ms

85%

异步+批量

98,000/s

2ms

62%

技术选型建议: 万级QPS以内首选Spring事件,超越则上MQ

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/3/3 13:03:51

Java版LeetCode热题100之单词拆分:从动态规划到面试实战的全面解析

Java版LeetCode热题100之单词拆分&#xff1a;从动态规划到面试实战的全面解析 本文深入剖析 LeetCode 第139题「单词拆分」&#xff0c;涵盖题目理解、算法设计、代码实现、复杂度分析、优化思路、数据结构基础、面试应对策略以及实际应用场景等多个维度&#xff0c;是一篇面向…

作者头像 李华
网站建设 2026/3/5 4:32:44

2026必备!8个AI论文平台,助你轻松搞定本科生毕业论文!

2026必备&#xff01;8个AI论文平台&#xff0c;助你轻松搞定本科生毕业论文&#xff01; AI 工具正在重塑论文写作的未来 在 2026 年&#xff0c;随着人工智能技术的不断进步&#xff0c;越来越多的学生开始依赖 AI 工具来辅助完成毕业论文。从最初的资料搜集到最终的格式调整…

作者头像 李华
网站建设 2026/2/27 21:59:51

构建自主同城配送平台,开源跑腿小程序系统的核心优势

温馨提示&#xff1a;文末有资源获取方式对于希望摆脱平台高额抽成、建立独立品牌与客户关系的创业者而言&#xff0c;一套功能完备、自主可控的技术方案至关重要。源码获取方式在源码闪购网。完全独立的品牌运营与用户沉淀系统支持私有化部署与全套UI自定义&#xff08;包括小…

作者头像 李华
网站建设 2026/3/5 1:32:12

java_ssm11办公电子政务管理系统 上下班考勤打卡系统

目录 具体实现截图办公电子政务管理系统与上下班考勤打卡系统摘要 系统所用技术介绍写作提纲源码文档获取/同行可拿货,招校园代理 &#xff1a;文章底部获取博主联系方式&#xff01; 具体实现截图 办公电子政务管理系统与上下班考勤打卡系统摘要 办公电子政务管理系统是基于…

作者头像 李华
网站建设 2026/3/3 20:05:19

怎么找国外的期刊?实用方法与渠道指南

刚开始做科研的时候&#xff0c;我一直以为&#xff1a; 文献检索就是在知网、Google Scholar 里反复换关键词。 直到后来才意识到&#xff0c;真正消耗精力的不是“搜不到”&#xff0c;而是—— 你根本不知道最近这个领域发生了什么。 生成式 AI 出现之后&#xff0c;学术检…

作者头像 李华