Appearance
事件机制
Spring 的事件机制是基于观察者模式实现的,用于在 Bean 之间进行解耦通信。一个 Bean 发布事件,其他 Bean 监听并处理,发布者和监听者之间不直接依赖。
一、事件机制三要素
① 事件(ApplicationEvent):
继承 ApplicationEvent 的消息体
② 发布者(ApplicationEventPublisher):
调用 publishEvent() 发布事件
③ 监听者(ApplicationListener / @EventListener):
接收并处理事件二、基本使用
java
// ① 定义事件
@Data
public class OrderCreatedEvent extends ApplicationEvent {
private Long orderId;
private Long userId;
public OrderCreatedEvent(Object source, Long orderId, Long userId) {
super(source);
this.orderId = orderId;
this.userId = userId;
}
}
// ② 发布事件
@Service
public class OrderService {
@Autowired
private ApplicationEventPublisher publisher;
@Transactional
public void createOrder(Order order) {
// 下单逻辑
orderMapper.insert(order);
// 发布事件
publisher.publishEvent(new OrderCreatedEvent(this, order.getId(), order.getUserId()));
}
}
// ③ 监听事件
@Component
public class OrderEventListener {
@EventListener
public void handleOrderCreated(OrderCreatedEvent event) {
System.out.println("订单创建成功:" + event.getOrderId());
// 发送短信通知
// 增加积分
// 记录日志
}
}三、@EventListener 详解
java
@Component
public class OrderEventListener {
// ① 基本监听
@EventListener
public void handleOrderCreated(OrderCreatedEvent event) {
// 处理逻辑
}
// ② 条件监听(SpEL 表达式)
@EventListener(condition = "#event.orderId > 1000")
public void handleBigOrder(OrderCreatedEvent event) {
// 只处理大订单
}
// ③ 异步监听(需要 @EnableAsync 开启)
@EventListener
@Async
public void handleAsync(OrderCreatedEvent event) {
// 异步处理,不阻塞主线程
}
// ④ 监听多个事件类型
@EventListener({OrderCreatedEvent.class, OrderCancelledEvent.class})
public void handleOrderEvents(Object event) {
// 处理多种事件
}
// ⑤ 监听 + 事务阶段(在事务提交后执行)
@EventListener
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
public void handleAfterCommit(OrderCreatedEvent event) {
// 事务提交后才执行,确保数据一致性
}
}四、@TransactionalEventListener
java
// 事务事件监听器:确保事件处理在事务提交/回滚后执行
@Component
public class OrderTransactionalListener {
// AFTER_COMMIT:事务提交后执行(默认,最常用)
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
public void handleAfterCommit(OrderCreatedEvent event) {
// 发送 MQ 消息、短信通知
// 此时数据已持久化,不会丢消息
}
// AFTER_ROLLBACK:事务回滚后执行
@TransactionalEventListener(phase = TransactionPhase.AFTER_ROLLBACK)
public void handleAfterRollback(OrderCreatedEvent event) {
// 记录回滚日志,补偿操作
}
// BEFORE_COMMIT:事务提交前执行
@TransactionalEventListener(phase = TransactionPhase.BEFORE_COMMIT)
public void handleBeforeCommit(OrderCreatedEvent event) {
// 提交前最后检查
}
// 错误处理
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT,
fallbackExecution = true) // 无事务时也执行
public void handleWithFallback(OrderCreatedEvent event) { }
}五、Spring 内置事件
| 事件 | 发布时间 | 用途 |
|---|---|---|
| ContextRefreshedEvent | 容器刷新完成 | 启动后初始化 |
| ContextStartedEvent | 容器启动 | 启动后任务 |
| ContextStoppedEvent | 容器停止 | 清理资源 |
| ContextClosedEvent | 容器关闭 | 最终清理 |
| RequestHandledEvent | 请求处理完成 | 请求统计 |
java
@Component
public class StartupListener {
@EventListener(ContextRefreshedEvent.class)
public void onApplicationReady(ContextRefreshedEvent event) {
System.out.println("应用启动完成,执行初始化任务...");
// 缓存预热
// 数据初始化
}
}六、事件机制底层原理
Spring 事件机制的核心类:
ApplicationEventMulticaster(事件广播器)
├─ SimpleApplicationEventMulticaster(默认实现)
│ ├─ 同步执行(默认):逐个调用所有监听器
│ └─ 异步执行(配置 TaskExecutor 后):线程池并发执行
└─ 自定义实现
publishEvent() 流程:
① 调用 ApplicationEventMulticaster.multicastEvent()
② 根据事件类型找到所有匹配的监听器
③ 遍历监听器,逐个调用 onApplicationEvent()
④ 如果是 @EventListener,通过反射调用标注的方法七、面试要点
Q1:Spring 事件机制的原理是什么?
基于观察者模式。ApplicationEventPublisher 发布事件,ApplicationEventMulticaster 广播事件给所有匹配的监听器。默认同步执行,配置 TaskExecutor 后可以异步执行。
Q2:@EventListener 和 @TransactionalEventListener 的区别?
@EventListener 在事件发布时立即执行(可能在事务中),@TransactionalEventListener 可以指定在事务提交后(AFTER_COMMIT)或回滚后(AFTER_ROLLBACK)执行。发 MQ 消息推荐用 @TransactionalEventListener(AFTER_COMMIT),保证数据已持久化。
Q3:Spring 事件和 MQ 的区别?
Spring 事件是进程内通信,简单、同步、不持久化;MQ 是跨进程通信,支持持久化、异步、消息回溯。Spring 事件适合单机解耦,MQ 适合分布式解耦。
