事件机制
Spring 事件机制基于观察者模式,允许 Bean 之间通过发布 / 订阅解耦通信,避免直接方法调用带来的强依赖。
核心组件
| 组件 | 说明 |
|---|---|
ApplicationEvent | 事件基类(Spring 4.2 后可发布任意对象) |
ApplicationEventPublisher | 发布事件的接口,注入即用 |
ApplicationListener<E> | 监听特定事件类型的接口 |
@EventListener | 注解方式监听,更简洁(推荐) |
ApplicationEventMulticaster | 事件多播器,负责将事件分发给监听器 |
基本用法
定义事件
// 方式一:继承 ApplicationEvent(携带 source)
public class OrderCreatedEvent extends ApplicationEvent {
private final Order order;
public OrderCreatedEvent(Object source, Order order) {
super(source);
this.order = order;
}
public Order getOrder() { return order; }
}
// 方式二:普通 POJO(Spring 4.2+,更简洁,推荐)
@Data
@AllArgsConstructor
public class OrderCreatedEvent {
private final Order order;
private final String operatorId;
}发布事件
@Service
@RequiredArgsConstructor
public class OrderService {
private final ApplicationEventPublisher eventPublisher;
@Transactional
public Order createOrder(CreateOrderRequest req) {
Order order = orderRepo.save(buildOrder(req));
// 事务提交前发布(默认同步,监听器在同一事务内执行)
eventPublisher.publishEvent(new OrderCreatedEvent(order, req.getOperatorId()));
return order;
}
}监听事件(@EventListener,推荐)
@Component
@Slf4j
public class OrderEventHandler {
private final NotificationService notificationService;
private final InventoryService inventoryService;
// 基本监听
@EventListener
public void onOrderCreated(OrderCreatedEvent event) {
log.info("订单创建事件: orderId={}", event.getOrder().getId());
notificationService.sendOrderConfirmation(event.getOrder());
}
// 条件过滤(SpEL):只处理金额大于 1000 的订单
@EventListener(condition = "#event.order.amount > 1000")
public void onHighValueOrder(OrderCreatedEvent event) {
notificationService.alertSalesManager(event.getOrder());
}
// 同时监听多个事件类型
@EventListener({OrderCreatedEvent.class, OrderUpdatedEvent.class})
public void onOrderChange(Object event) {
inventoryService.recalculate();
}
}接口方式(适合泛型、复杂场景)
@Component
public class AuditLogListener implements ApplicationListener<OrderCreatedEvent> {
@Override
public void onApplicationEvent(OrderCreatedEvent event) {
auditLogService.record(event.getOrder());
}
}异步事件
默认事件同步执行(监听器在发布者线程中运行)。加 @Async 让监听器在线程池中异步执行:
@Configuration
@EnableAsync // 启用异步,一般放在启动类或配置类
public class AsyncConfig {
@Bean(name = "eventExecutor")
public Executor eventExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(4);
executor.setMaxPoolSize(8);
executor.setQueueCapacity(100);
executor.setThreadNamePrefix("event-");
executor.initialize();
return executor;
}
}
@Component
public class EmailNotificationListener {
// 在 eventExecutor 线程池中异步执行,不阻塞发布者线程
@Async("eventExecutor")
@EventListener
public void sendEmail(OrderCreatedEvent event) {
// 耗时操作:发送邮件
emailService.send(event.getOrder().getUserEmail());
}
}异步监听器运行在独立线程中,不参与发布者的事务,异常也不会回滚发布者的事务。
异步与线程池详见 异步与线程池。
事务事件监听(@TransactionalEventListener)
常见需求:订单创建成功提交后再发送通知,若事务回滚则不发送。
@Component
@Slf4j
public class OrderTransactionalHandler {
// 默认 phase = AFTER_COMMIT:事务提交成功后才执行
@TransactionalEventListener
public void afterCommit(OrderCreatedEvent event) {
// 此时订单数据已持久化,可以安全发送通知
notificationService.sendSms(event.getOrder());
}
// 事务回滚后执行(用于补偿、告警)
@TransactionalEventListener(phase = TransactionPhase.AFTER_ROLLBACK)
public void afterRollback(OrderCreatedEvent event) {
log.error("订单创建事务回滚: orderId={}", event.getOrder().getId());
alertService.notifyDeveloper(event);
}
// 无论提交还是回滚都执行
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMPLETION)
public void afterCompletion(OrderCreatedEvent event) {
// 清理临时资源
}
// 事务提交前执行(可以修改事务内的数据)
@TransactionalEventListener(phase = TransactionPhase.BEFORE_COMMIT)
public void beforeCommit(OrderCreatedEvent event) {
auditLogService.record(event.getOrder());
}
}| Phase | 触发时机 |
|---|---|
BEFORE_COMMIT | 事务提交前(仍在事务内) |
AFTER_COMMIT(默认) | 事务提交后 |
AFTER_ROLLBACK | 事务回滚后 |
AFTER_COMPLETION | 事务完成后(提交或回滚) |
@TransactionalEventListener要求发布者必须在事务中运行,否则默认不触发(可设fallbackExecution = true在无事务时也执行)。
事务管理详见 事务管理。
有序监听(@Order)
同一事件有多个监听器时,通过 @Order 控制执行顺序(数值越小越先执行):
@EventListener
@Order(1)
public void validateOrder(OrderCreatedEvent event) {
// 先校验
}
@EventListener
@Order(2)
public void deductInventory(OrderCreatedEvent event) {
// 再扣库存
}
@EventListener
@Order(3)
public void sendNotification(OrderCreatedEvent event) {
// 最后通知
}泛型事件
// 泛型事件:EntityCreatedEvent<Order>、EntityCreatedEvent<User> 分别触发不同监听器
public class EntityCreatedEvent<T> {
private final T entity;
public EntityCreatedEvent(T entity) { this.entity = entity; }
public T getEntity() { return entity; }
}
// 只监听 Order 的创建事件,User 的创建不会触发
@EventListener
public void onOrderCreated(EntityCreatedEvent<Order> event) {
log.info("订单实体创建: {}", event.getEntity().getId());
}Spring 内置生命周期事件
| 事件 | 触发时机 |
|---|---|
ApplicationStartingEvent | SpringApplication 启动,Environment 未初始化 |
ApplicationEnvironmentPreparedEvent | Environment 准备好,容器未创建 |
ApplicationContextInitializedEvent | ApplicationContext 创建并初始化 |
ApplicationPreparedEvent | BeanDefinition 加载完毕,未刷新 |
ContextRefreshedEvent | 容器刷新完成(所有 Bean 就绪) |
ApplicationStartedEvent | 容器刷新完成,Runner 执行前 |
ApplicationReadyEvent | Runner 执行完毕,应用就绪接受请求 |
ApplicationFailedEvent | 启动过程中发生异常 |
ContextClosedEvent | 容器关闭 |
@Component
public class AppLifecycleListener {
@EventListener(ApplicationReadyEvent.class)
public void onReady() {
log.info("应用启动完毕,开始接受请求");
cacheService.warmup(); // 缓存预热
}
@EventListener(ContextClosedEvent.class)
public void onClose() {
log.info("应用即将关闭,清理资源");
}
}启动流程详见 启动流程。
事件 vs 直接调用 vs 消息队列
| 对比 | 直接方法调用 | Spring 事件 | 消息队列(MQ) |
|---|---|---|---|
| 耦合度 | 强(直接依赖) | 弱(依赖事件类) | 最弱(无依赖) |
| 可靠性 | 同步、强一致 | 进程内,无持久化 | 持久化,可重试 |
| 跨服务 | 不支持 | 不支持 | 支持 |
| 事务支持 | 同一事务 | @TransactionalEventListener | 本地消息表 |
| 适用场景 | 强依赖、同步逻辑 | 同进程解耦、生命周期扩展 | 跨服务、高可靠 |
跨服务事件驱动详见 消息队列。