news 2026/3/4 20:12:14

用Spring的ApplicationEventPublisher进行事件发布和监听

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
用Spring的ApplicationEventPublisher进行事件发布和监听

概述

有时候,我们只是想发布一些本地的事件,并不需要引入MQ的,可以直接使用Spring的ApplicationEventPublisher来完成简单事件的发布和监听的。

比如像下面的场景,ApplicationEventPublisher就够用了。

  • 模块间的逻辑解耦,但不跨服务;
  • 轻量级的本地事件通知
  • 应用内部的解耦和扩展点:比如说在DDD里,聚合保存数据成功后,需要触发若干的后续动作
  • 无强事务要求、无强持久化要求的通知场景

生产环境实战,门店创建成功后发布【门店已成功创建的事件】

在我目前这边,门店一旦创建成功后,是有很多一系列的后续动作要去做的,比如配置门店的各种各样的规则信息。

具体的代码很简单。

  • 就是用ApplicationEventPublisher的publishEvent方法发布事件
  • 用EventListener注解监听事件就可以了。

具体的代码实现如下。

事件发布者封装 ApplicationEventPublisher

ShopCreationEventPublisher对 Spring 的ApplicationEventPublisher做了一层封装,统一事件创建和日志输出:

@Component @RequiredArgsConstructor @Slf4j public class ShopCreationEventPublisher { private final ApplicationEventPublisher applicationEventPublisher; public void publishShopCreationEvent(Long shopId) { if (shopId == null) { return; } applicationEventPublisher.publishEvent( new ShopCreationEvent( shopId, ShopConstant.ShopDomainEvent.SHOP_CREATION_EVENT.getCode() ) ); log.info("Publishing {} for shopId: {}", ShopConstant.ShopDomainEvent.SHOP_CREATION_EVENT.getCode(), shopId); } }
@AllArgsConstructor @Getter public enum ShopDomainEvent { SHOP_CREATION_EVENT("shop_creation_event", "门店已创建"), SHOP_UPDATE_EVENT("shop_update_event", "门店已更新"); /** * 编码 */ private final String code; /** * 描述 */ private final String desc; }

这个类做了几件小事:

  • 封装事件构造:上层只需要传shopId,不关心事件 code 的细节
  • ShopDomainEvent:定义门店的时间,有创建和更新

通过这层封装,业务代码几乎完全与ApplicationEventPublisher解耦,只依赖一个语义明确的发布器。ShopApplicationService类只需要调用发布方法,事件就发布出去了。

@RequiredArgsConstructor @Service @Slf4j public class ShopApplicationService { private final ShopCreationEventPublisher shopCreationEventPublisher; /** * 保存门店聚合信息 */ public void saveShopInfo(SaveShopInfoCommand saveShopInfoCommand) { // 构建聚合根 ShopInfoAggregateRoot root = shopInfoFactory.createShopInfoAggregateRoot(saveShopInfoCommand); // 持久化 shopInfoRepository.persistence(root); // 发布【门店已创建】的事件 shopCreationEventPublisher.publishShopCreationEvent(root.getId()); } }

事件监听者实现

用EventListener注解就可以了。

@Component @Slf4j @RequiredArgsConstructor class NewShopRuleGenerateListener { @EventListener public void onShopCreationEvent(ShopCreationEvent event) { log.info("NewShopRuleGenerateListener received : {}", JSON.toJSONString(event)); Long shopId = event.getShopId(); if (shopId == null) { return; } // 新启一个线程执行,避免阻塞事件发布线程 new Thread(() -> { ShopInfoAggregateRoot shopInfoAggregateRoot = shopInfoRepository.selectByShopId(shopId.intValue()); // 新增的门店配置各种各样的规则 }).start(); }

可以看出:

  • 监听方式非常直观:通过@EventListener标注方法,参数就是要监听的事件类型ShopCreationEvent
  • 业务逻辑完全从ShopApplicationService中拆了出来,转移到一个职责清晰的监听器类里
  • 为避免阻塞事件发布线程,监听器内部主动使用新线程执行耗时操作

这条链路的好处在于:

  • 保存门店的主流程对“谁在监听这个事件”是无感知的;
  • 新增或删除监听器只影响监听方代码,不需要修改ShopApplicationService

实战落地建议

尽量为每类事件提供单独的发布器

  • 比如ShopCreationEventPublisherShopUpdatePublisher,而不是在业务代码里直接拿ApplicationEventPublisher
  • 便于后续在发布器层面统一做日志、限流或埋点

事件命名和字段保持业务语义清晰

  • ShopCreationEvent这种名称比“门店变更事件”更具体
  • 事件体只放必要字段,比如shopId、事件类型 code,避免变成“大而全 DTO`

监听器职责要单一

  • 一个监听器专注做一件事情
  • 如果后续还有“新门店初始化库存”、“新门店推送消息”等,可以新建监听器按职责拆分

异步处理尽早抽象到统一机制

  • 目前上面的代码使用new Thread。这个是不太合理的, 应该是用线程池。

在不引入 MQ 的前提下,基于 ApplicationEventPublisher 的这种本地事件机制,可以在保持代码结构清晰的同时,给系统预留足够的扩展点,对很多中小体量的业务来说,这种方案已经足够实用。

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

储能系统绝缘监测的技术突破:微电流传感器在直流侧的应用与优化

引言 随着全球储能市场的爆发式增长,系统安全性成为行业关注的焦点。根据中国电力科学研究院数据,2025年储能电站因绝缘故障导致的事故占比高达15%,其中直流侧漏电流监测不足是主要诱因。微电流传感器(如基于磁通门或高精度霍尔原…

作者头像 李华
网站建设 2026/3/2 22:44:19

leetcode 困难题 871. Minimum Number of Refueling Stops 最低加油次数-内存100

Problem: 871. Minimum Number of Refueling Stops 最低加油次数 解题过程 内存100%,状态数组标记是否被使用,每次从当前能到达的最远的地方,期间所有的加油站选择油最多的站点,不停循环直到可以到达目的地 Code using pr pair&…

作者头像 李华
网站建设 2026/3/3 0:01:49

解读GB/T4857.5跌落测试标准 助力医药包装NMPA注册合规

在医疗器械、生物制药、敷料、疫苗等行业,产品的运输安全直接关系到临床使用效果与患者生命健康,而运输包装作为产品的“防护屏障”,其耐冲击性能至关重要。GB/T4857.5-92《包装 运输包装件 跌落试验方法》作为国内运输包装冲击测试的核心标准…

作者头像 李华
网站建设 2026/3/3 18:18:54

VP引导定位软件-平移九点标定

VP引导定位软件-平移九点标定 一 确定通讯协议 Calib,X,Y,第几个点Calib,140,10,1 Calib,140,-10,2 Calib,140,-30,3 Calib,160,10,4 Calib,160,-10,5 Calib,160,-30,6 Calib,180,10,7 Calib,180,-10,8 Calib,180,-30,9二 定义全局变量/// <summary>/// 软件模式/// Loca…

作者头像 李华
网站建设 2026/2/28 21:54:21

安全扫描器漏检97%的AI生成后门:现代开发流程的隐形危机

会员专属故事&#xff1a;你的安全扫描器漏检了97%的AI生成后门 作者&#xff1a;Ahmed Abdelmenem 阅读时间&#xff1a;8分钟3天前 72次收听 分享 研究表明&#xff0c;即使是专门的检测工具也会失效——每一个开发冲刺都将脆弱的代码交付到了生产环境。 &#xff08;按回车键…

作者头像 李华
网站建设 2026/3/2 1:43:31

实战|Dify 零代码智能体开发:从需求设计到落地部署全流程

点赞、关注、收藏&#xff0c;不迷路 点赞、关注、收藏&#xff0c;不迷路 Dify 作为可视化、零代码 / 低代码的 LLM 应用开发平台&#xff0c;无需深厚编程基础即可快速搭建智能体。本文以 「工程师专属 AI 技术助手」 为例&#xff0c;拆解从需求设计、功能搭建、测试优化到落…

作者头像 李华