1089 字
约 3 分钟
7
S07-J03 · Spring Event:事件发布订阅

适用读者:想解耦"下单后要发短信/加积分/写日志"这类逻辑的人。
前置:S07-B02、S07-J02。
实测环境:Spring Boot 3.3.6 / JDK 17(2026-11-05)。
覆盖旧文:634(469) 386(144) = 613 点。
覆盖扩展:E-S07-015(同步 vs 异步、事务边界)。
上一篇:S07-J02 · 循环依赖与三级缓存
下一篇:S07-J04 · 定时任务与异步。


1. 一句话结论

默认事件是同步的:publishEvent 会在当前线程把监听器全部执行完才返回。要异步必须显式 @Async + 线程池。

实测输出(顺序即事实):

[1] 发布事件前
[2] 同步监听: A100
[3] 发布事件后
[async] 异步监听: A100 线程=task-1

读法:

观察 结论
[2] 在 [3] 之前 同步监听阻塞了发布方
[async] 在 [3] 之后、线程是 task-1 异步监听在独立线程池执行

2. 三个组件

组件 作用
ApplicationEventPublisher 发布(publishEvent)
@EventListener 监听(方法参数即事件类型)
事件类 任意 POJO(Boot 4.2+/Spring 4.2+ 不强制继承 ApplicationEvent)
record OrderPaid(String id) {}

@Component class Listener {
    @EventListener void on(OrderPaid e) { /* 同步 */ }
    @Async @EventListener void onAsync(OrderPaid e) { /* 异步 */ }
}

3. 同步 vs 异步(E-S07-015)

维度 同步(默认) 异步(@Async)
线程 发布方线程 线程池(task-N)
发布方是否等待 等待 不等
异常传播 会抛回发布方 被 AsyncUncaughtExceptionHandler 接
事务边界 同一事务(可参与回滚) 不在同一事务
适用 强一致(如扣库存) 最终一致(发短信、加积分)

判据:"这段逻辑失败要不要连累主流程?" 要 → 同步;不要 → 异步(但要接受"可能失败")。


4. 事务边界:最容易踩的坑(A-386)

问题:在事务方法里 publishEvent,同步监听器会在事务提交前执行——监听器里查不到未提交的数据。

方案 做法
@TransactionalEventListener(phase = AFTER_COMMIT) 提交后再执行(推荐)
@TransactionalEventListener(phase = BEFORE_COMMIT) 提交前(能参与回滚)
异步 + 事务 注意"事件发出但事务回滚"导致的不一致

判据:"监听器需要读到本次事务的写结果吗?" 需要 → AFTER_COMMIT。


5. 事件机制的适用边界

适合 不适合
主流程不关心结果的副作用(通知、统计) 必须与主流程同生共死的逻辑(用同步调用)
跨模块解耦(订单 → 积分/消息) 强顺序、强一致的核心链路
替代"反向依赖"(J02 的循环依赖) 高频大数据量(进程内事件不适合做消息队列)

与 MQ 的区别:Spring Event 是进程内的,应用重启/多实例时不会跨进程投递——需要可靠性就用 MQ(S17)。


6. 五个误区

误区 真相
"事件默认是异步的" 默认同步(实测 [2] 阻塞 [3])
"异步监听会参与事务" 不在同一事务
"事件能替代 MQ" 只在本进程内
"@EventListener 能保证顺序" 同步按注册顺序;异步不保证
"监听器异常不会影响主流程" 同步监听器异常会抛回发布方

7. 自检

  1. 默认事件是同步还是异步?实测怎么证明?
  2. @Async 监听器在哪个线程执行?异常谁处理?
  3. 为什么要在 AFTER_COMMIT 阶段监听?
  4. Spring Event 与 MQ 的本质区别?
  5. 哪类逻辑不该用事件?

8. 下一篇

S07-J04 · 定时任务与异步:@Scheduled / 线程池 / 重试

事件讲完,下一篇讲"按时间触发":默认调度器只有一个线程(实测 scheduling-1),以及重试组件的设计。


本篇属于系列《S07 · Spring 框架》。旧文来源:A-634/386;扩展点 E-S07-015。同步/异步顺序与线程名为 Spring Boot 3.3.6 实测。

S07-J03 · Spring Event:事件发布订阅
https://www.clxhxhhr.top/posts/5276/
作者
clxstart
发布于
2024-12-31
许可协议
CC BY-NC-SA 4.0
评论
0 条
还没有评论,先写一条吧。