Spring事件驱动机制
约 1391 字大约 5 分钟
springevent
2025-04-07
概述
Spring 事件驱动机制是基于观察者模式实现的应用内事件发布-订阅系统。它允许组件之间通过事件进行松耦合的通信,而不需要直接依赖。Spring 提供了 ApplicationEvent、ApplicationEventPublisher、@EventListener 等核心 API,支持同步/异步事件、事务绑定事件和条件过滤等高级特性。
事件机制架构
基本使用
1. 定义事件
// 方式一:继承 ApplicationEvent(传统方式)
public class OrderCreatedEvent extends ApplicationEvent {
private final String orderId;
private final String userId;
private final BigDecimal amount;
public OrderCreatedEvent(Object source, String orderId, String userId,
BigDecimal amount) {
super(source);
this.orderId = orderId;
this.userId = userId;
this.amount = amount;
}
public String getOrderId() { return orderId; }
public String getUserId() { return userId; }
public BigDecimal getAmount() { return amount; }
}
// 方式二:POJO 事件(Spring 4.2+ 推荐,无需继承ApplicationEvent)
public record OrderPaidEvent(String orderId, String userId, BigDecimal amount,
LocalDateTime paidAt) {}
public record UserRegisteredEvent(Long userId, String email, String username) {}2. 发布事件
@Service
public class OrderService {
@Autowired
private ApplicationEventPublisher eventPublisher;
@Transactional
public Order createOrder(CreateOrderRequest request) {
Order order = new Order(request);
orderRepository.save(order);
// 发布事件(Spring 4.2+ 支持任意对象作为事件)
eventPublisher.publishEvent(
new OrderCreatedEvent(this, order.getId(),
request.getUserId(), order.getAmount()));
return order;
}
@Transactional
public void payOrder(String orderId) {
Order order = orderRepository.findById(orderId)
.orElseThrow();
order.setStatus("PAID");
order.setPaidAt(LocalDateTime.now());
orderRepository.save(order);
eventPublisher.publishEvent(
new OrderPaidEvent(orderId, order.getUserId(),
order.getAmount(), order.getPaidAt()));
}
}3. 监听事件
// 方式一:@EventListener 注解(推荐)
@Component
public class OrderEventListener {
@EventListener
public void handleOrderCreated(OrderCreatedEvent event) {
log.info("Order created: {}, amount: {}", event.getOrderId(), event.getAmount());
// 发送订单确认短信
smsService.sendOrderConfirmation(event.getUserId(), event.getOrderId());
}
@EventListener
public void handleOrderPaid(OrderPaidEvent event) {
log.info("Order paid: {}", event.orderId());
// 更新库存
inventoryService.reduceStock(event.orderId());
}
}
// 方式二:实现 ApplicationListener 接口
@Component
public class EmailNotificationListener implements ApplicationListener<OrderCreatedEvent> {
@Override
public void onApplicationEvent(OrderCreatedEvent event) {
emailService.sendOrderEmail(event.getUserId(), event.getOrderId());
}
}@EventListener 高级用法
条件过滤
@Component
public class ConditionalEventListener {
// 仅处理金额大于1000的订单
@EventListener(condition = "#event.amount.compareTo(T(java.math.BigDecimal).valueOf(1000)) > 0")
public void handleHighValueOrder(OrderCreatedEvent event) {
log.info("High value order detected: {} ({})",
event.getOrderId(), event.getAmount());
riskService.checkOrder(event.getOrderId());
}
// 监听多个事件类型
@EventListener({OrderCreatedEvent.class, OrderPaidEvent.class})
public void handleOrderEvents(Object event) {
log.info("Order event received: {}", event.getClass().getSimpleName());
}
}事件链(返回值作为新事件发布)
@Component
public class EventChainListener {
// 返回值会被自动作为新事件发布
@EventListener
public OrderVerifiedEvent handleOrderCreated(OrderCreatedEvent event) {
boolean verified = verificationService.verify(event.getOrderId());
return new OrderVerifiedEvent(event.getOrderId(), verified);
}
@EventListener
public void handleOrderVerified(OrderVerifiedEvent event) {
if (event.isVerified()) {
log.info("Order verified: {}", event.orderId());
}
}
}异步事件处理
// 1. 启用异步支持
@Configuration
@EnableAsync
public class AsyncConfig {
@Bean("eventTaskExecutor")
public TaskExecutor eventTaskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(5);
executor.setMaxPoolSize(20);
executor.setQueueCapacity(100);
executor.setThreadNamePrefix("event-");
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.initialize();
return executor;
}
}
// 2. 在监听器上标注 @Async
@Component
public class AsyncEventListener {
@Async("eventTaskExecutor")
@EventListener
public void handleOrderCreatedAsync(OrderCreatedEvent event) {
// 在独立线程中执行,不阻塞发布者
log.info("Async handling order: {} on thread: {}",
event.getOrderId(), Thread.currentThread().getName());
notificationService.pushNotification(event.getUserId(),
"Your order " + event.getOrderId() + " has been created");
}
}@TransactionalEventListener
在事务场景中,常常需要在事务提交后才执行某些操作(如发送通知),避免事务回滚后仍然发出了通知。
@Component
public class TransactionalEventHandler {
// 事务提交后执行(默认)
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
public void onOrderCreatedAfterCommit(OrderCreatedEvent event) {
// 数据已持久化,安全地发送通知
notificationService.sendPushNotification(event.getUserId(),
"Order " + event.getOrderId() + " confirmed");
}
// 事务回滚后执行
@TransactionalEventListener(phase = TransactionPhase.AFTER_ROLLBACK)
public void onOrderCreatedRollback(OrderCreatedEvent event) {
log.warn("Order creation rolled back: {}", event.getOrderId());
metricsService.incrementCounter("order.creation.rollback");
}
// 事务完成后执行(无论提交还是回滚)
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMPLETION)
public void onOrderCreatedCompletion(OrderCreatedEvent event) {
// 清理临时资源
tempFileService.cleanup(event.getOrderId());
}
// 事务提交前执行
@TransactionalEventListener(phase = TransactionPhase.BEFORE_COMMIT)
public void onOrderCreatedBeforeCommit(OrderCreatedEvent event) {
// 在同一事务中执行额外的数据库操作
auditLogService.logOrderCreation(event.getOrderId());
}
}自定义事件总线
@Component
public class DomainEventBus {
@Autowired
private ApplicationEventPublisher publisher;
private final List<Object> deferredEvents = new ArrayList<>();
public void publish(Object event) {
publisher.publishEvent(event);
}
public void defer(Object event) {
deferredEvents.add(event);
}
public void flushDeferredEvents() {
deferredEvents.forEach(publisher::publishEvent);
deferredEvents.clear();
}
}Spring 内置事件
@Component
public class SpringLifecycleListener {
@EventListener
public void handleContextRefreshed(ContextRefreshedEvent event) {
log.info("ApplicationContext refreshed");
}
@EventListener
public void handleContextStarted(ContextStartedEvent event) {
log.info("ApplicationContext started");
}
@EventListener
public void handleContextStopped(ContextStoppedEvent event) {
log.info("ApplicationContext stopped");
}
@EventListener
public void handleContextClosed(ContextClosedEvent event) {
log.info("ApplicationContext closed");
}
// Spring Boot 特有事件
@EventListener
public void handleApplicationReady(ApplicationReadyEvent event) {
log.info("Application is ready to serve requests");
warmUpService.warmUpCaches();
}
}事件 vs 直接调用
| 对比维度 | 直接调用 | 事件驱动 |
|---|---|---|
| 耦合度 | 高 | 低 |
| 扩展性 | 需修改调用方 | 新增监听器即可 |
| 调试难度 | 低 | 中(链路不直观) |
| 事务一致性 | 容易保证 | 需要额外处理 |
| 适用场景 | 核心业务逻辑 | 附属/通知类逻辑 |
总结
Spring 事件驱动机制通过发布-订阅模式实现组件间松耦合通信。@EventListener 简化了监听器的编写,@Async 支持异步处理,@TransactionalEventListener 保证事务安全。事件机制适合处理附属逻辑(通知、日志、统计等),将核心业务与非核心逻辑解耦。对于跨服务的事件通信,则需要引入消息队列(如 RabbitMQ、Kafka)。
贡献者
更新日志
2026/3/14 13:09
查看所有更新日志
9f6c2-feat: organize wiki content and refresh site setup于