事件机制:@EventListener 与异步事件
引言
业务里“下单成功要发短信、记日志、送积分”——若全部写在下单方法里,每次加新动作都要改主流程。事件机制把“发生什么”(事件)与“怎么响应”(监听器)解耦:主流程只 publishEvent,关心的人各自监听。本章掌握发布/监听/异步三件事。
核心概念
- 发布端:注入
ApplicationEventPublisher,调publishEvent(Object)——Spring 4.2 起任意 POJO 都可作事件(不是 ApplicationEvent 的会被包装成 PayloadApplicationEvent,以官方文档为准)。 - 监听端:
@EventListener(org.springframework.context.event)标在 Bean 的 public 方法上,方法参数即事件类型;容器据此匹配事件。 - 条件监听:
@EventListener(condition = "#ev.success"),SpEL 里方法参数名可直接引用(详见第 18 章)。 - 返回值进阶:监听方法有返回值时,返回值会作为新事件再次发布(可做事件链)。
- 事务事件:
@TransactionalEventListener默认在事务 AFTER_COMMIT 后触发,避免“事务没提交就发事件”;无事务且未开fallbackExecution时不触发(以官方文档为准)。 - 默认同步:发布线程逐个调用监听器,监听器异常会传回发布方。
- 异步两种姿势:①监听方法上加
@Async+ 开启@EnableAsync;②自定义applicationEventMulticasterBean(SimpleApplicationEventMulticaster.setTaskExecutor(executor))统一异步。多监听器顺序用@Order。
代码示例
// 1) 事件:普通 POJO 即可
public record OrderCreated(Long orderId, boolean success) {}
// 2) 发布端
@Service
public class OrderService {
private final ApplicationEventPublisher publisher;
public OrderService(ApplicationEventPublisher publisher) { this.publisher = publisher; }
public void create() {
// ...下单逻辑...
publisher.publishEvent(new OrderCreated(1001L, true)); // 发完即走,不关心谁听
}
}
// 3) 监听端:一个类可挂多个监听方法
@Component
public class OrderListeners {
@EventListener
public void onCreated(OrderCreated ev) {
System.out.println("记录日志 orderId=" + ev.orderId());
}
@EventListener(condition = "#ev.success")
@Async // 异步执行:需 @EnableAsync
public void sendSms(OrderCreated ev) {
System.out.println("异步发短信 orderId=" + ev.orderId());
}
}
// 4) 事务提交后再发通知
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT,
fallbackExecution = true)
public void onCommitted(OrderCreated ev) { /* 事务已提交才执行 */ }
注意点
- 默认同步意味着监听器里别做慢操作,否则拖慢发布方;要快就异步化。
- 异步监听器(@Async 或异步 multicaster)的异常不会自动传回发布方,需在监听器内部自行捕获记录(以官方文档为准)。
@Async走代理,同类自调用同样失效(回顾第 13 章);同时记得配线程池执行器,别依赖框架默认的简单执行器。- 事务事件必须等事务真的提交才触发;误以为“方法一执行就发事件”会读到未提交数据。
- 事件只解耦“通知”,别在监听器里反写主流程数据造成隐式依赖环。
小结
事件机制 = 发布 POJO 事件 + @EventListener 匹配订阅 + 可选条件/事务相位/异步化。默认同步、可异步、可延迟到事务提交后,是 Spring 应用内模块解耦(含跨 Bean 解环)的利器。