跳到主要内容

事件机制

Spring 的事件机制是基于观察者模式的实现,允许 Bean 之间进行松耦合的通信。本章介绍 Spring 事件的发布与监听机制。

事件机制概述

Spring 事件机制包含三个核心概念:

事件(Event):需要被传递的信息载体,继承自 ApplicationEvent。

事件发布者(Publisher):发布事件的组件,实现 ApplicationEventPublisherAware 接口或注入 ApplicationEventPublisher。

事件监听器(Listener):处理事件的组件,实现 ApplicationListener 接口或使用 @EventListener 注解。

自定义事件

创建事件类

public class UserCreatedEvent extends ApplicationEvent {

private final Long userId;
private final String username;

public UserCreatedEvent(Object source, Long userId, String username) {
super(source);
this.userId = userId;
this.username = username;
}

public Long getUserId() {
return userId;
}

public String getUsername() {
return username;
}
}

public class OrderCompletedEvent extends ApplicationEvent {

private final Long orderId;
private final BigDecimal amount;
private final LocalDateTime completedAt;

public OrderCompletedEvent(Object source, Long orderId, BigDecimal amount) {
super(source);
this.orderId = orderId;
this.amount = amount;
this.completedAt = LocalDateTime.now();
}

public Long getOrderId() {
return orderId;
}

public BigDecimal getAmount() {
return amount;
}

public LocalDateTime getCompletedAt() {
return completedAt;
}
}

发布事件

@Service
public class UserService {

@Autowired
private ApplicationEventPublisher eventPublisher;

@Autowired
private UserDao userDao;

public User createUser(User user) {
User savedUser = userDao.save(user);

eventPublisher.publishEvent(new UserCreatedEvent(this, savedUser.getId(), savedUser.getName()));

return savedUser;
}
}

也可以通过实现 ApplicationEventPublisherAware 接口获取发布者:

@Service
public class OrderService implements ApplicationEventPublisherAware {

private ApplicationEventPublisher eventPublisher;

@Autowired
private OrderDao orderDao;

@Override
public void setApplicationEventPublisher(ApplicationEventPublisher eventPublisher) {
this.eventPublisher = eventPublisher;
}

public void completeOrder(Long orderId) {
Order order = orderDao.findById(orderId);
order.setStatus(OrderStatus.COMPLETED);
orderDao.save(order);

eventPublisher.publishEvent(new OrderCompletedEvent(this, orderId, order.getAmount()));
}
}

监听事件

使用 @EventListener 注解

@Component
@Slf4j
public class UserEventListener {

@EventListener
public void onUserCreated(UserCreatedEvent event) {
log.info("用户创建成功: userId={}, username={}", event.getUserId(), event.getUsername());
}

@EventListener
public void onOrderCompleted(OrderCompletedEvent event) {
log.info("订单完成: orderId={}, amount={}", event.getOrderId(), event.getAmount());
}
}

使用 ApplicationListener 接口

@Component
public class UserCreatedListener implements ApplicationListener<UserCreatedEvent> {

@Override
public void onApplicationEvent(UserCreatedEvent event) {
System.out.println("收到用户创建事件: " + event.getUsername());
}
}

条件监听

使用 SpEL 表达式进行条件过滤:

@Component
public class VipUserEventListener {

@EventListener(condition = "#event.userType == 'VIP'")
public void onVipUserCreated(UserCreatedEvent event) {
System.out.println("VIP用户创建: " + event.getUsername());
}
}

监听多个事件

@Component
public class MultiEventListener {

@EventListener({UserCreatedEvent.class, OrderCompletedEvent.class})
public void onMultipleEvents(ApplicationEvent event) {
if (event instanceof UserCreatedEvent) {
System.out.println("用户事件");
} else if (event instanceof OrderCompletedEvent) {
System.out.println("订单事件");
}
}
}

异步事件

默认情况下,事件监听器是同步执行的,会阻塞发布者。使用 @Async 可以异步处理事件:

启用异步支持

@Configuration
@EnableAsync
public class AsyncConfig {

@Bean
public Executor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(5);
executor.setMaxPoolSize(10);
executor.setQueueCapacity(100);
executor.setThreadNamePrefix("event-");
executor.initialize();
return executor;
}
}

异步监听器

@Component
public class AsyncEventListener {

@Async
@EventListener
public void onUserCreated(UserCreatedEvent event) {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
System.out.println("异步处理用户创建事件: " + event.getUsername());
}
}

事务绑定事件

Spring 4.2 引入了事务绑定事件,可以在事务的不同阶段触发:

@Component
public class TransactionalEventListener {

@TransactionalEventListener(phase = TransactionPhase.BEFORE_COMMIT)
public void beforeCommit(UserCreatedEvent event) {
System.out.println("事务提交前: " + event.getUsername());
}

@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
public void afterCommit(UserCreatedEvent event) {
System.out.println("事务提交后: " + event.getUsername());
}

@TransactionalEventListener(phase = TransactionPhase.AFTER_ROLLBACK)
public void afterRollback(UserCreatedEvent event) {
System.out.println("事务回滚后: " + event.getUsername());
}

@TransactionalEventListener(phase = TransactionPhase.AFTER_COMPLETION)
public void afterCompletion(UserCreatedEvent event) {
System.out.println("事务完成后: " + event.getUsername());
}
}

事务绑定事件的典型应用场景:

发送邮件通知:事务提交成功后再发送邮件,避免事务回滚但邮件已发送的情况。

更新缓存:事务提交成功后再更新缓存,保证数据一致性。

异步处理:事务提交后触发异步任务。

内置事件

Spring 提供了一些内置事件:

事件触发时机
ContextRefreshedEventApplicationContext 初始化或刷新完成
ContextStartedEventApplicationContext 启动
ContextStoppedEventApplicationContext 停止
ContextClosedEventApplicationContext 关闭
RequestHandledEvent请求处理完成(Web 应用)
@Component
public class ContextEventListener {

@EventListener
public void onContextRefreshed(ContextRefreshedEvent event) {
System.out.println("应用上下文刷新完成");
}

@EventListener
public void onContextClosed(ContextClosedEvent event) {
System.out.println("应用上下文关闭");
}
}

实际应用示例

用户注册流程

public class UserRegisteredEvent extends ApplicationEvent {
private final User user;

public UserRegisteredEvent(Object source, User user) {
super(source);
this.user = user;
}

public User getUser() {
return user;
}
}

@Service
public class UserService {

@Autowired
private ApplicationEventPublisher eventPublisher;

@Autowired
private UserDao userDao;

public User register(User user) {
User savedUser = userDao.save(user);
eventPublisher.publishEvent(new UserRegisteredEvent(this, savedUser));
return savedUser;
}
}

@Component
public class UserRegisteredEventListener {

@Autowired
private EmailService emailService;

@Autowired
private PointService pointService;

@Autowired
private NotificationService notificationService;

@Async
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
public void sendWelcomeEmail(UserRegisteredEvent event) {
emailService.sendWelcomeEmail(event.getUser().getEmail());
}

@Async
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
public void grantInitialPoints(UserRegisteredEvent event) {
pointService.grantPoints(event.getUser().getId(), 100);
}

@Async
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
public void notifyAdmin(UserRegisteredEvent event) {
notificationService.notifyAdmin("新用户注册: " + event.getUser().getName());
}
}

订单状态变更

public class OrderStatusChangedEvent extends ApplicationEvent {
private final Long orderId;
private final OrderStatus oldStatus;
private final OrderStatus newStatus;

public OrderStatusChangedEvent(Object source, Long orderId, OrderStatus oldStatus, OrderStatus newStatus) {
super(source);
this.orderId = orderId;
this.oldStatus = oldStatus;
this.newStatus = newStatus;
}
}

@Service
public class OrderService {

@Autowired
private ApplicationEventPublisher eventPublisher;

@Autowired
private OrderDao orderDao;

@Transactional
public void updateStatus(Long orderId, OrderStatus newStatus) {
Order order = orderDao.findById(orderId);
OrderStatus oldStatus = order.getStatus();
order.setStatus(newStatus);
orderDao.save(order);

eventPublisher.publishEvent(new OrderStatusChangedEvent(this, orderId, oldStatus, newStatus));
}
}

@Component
public class OrderStatusEventListener {

@EventListener(condition = "#event.newStatus == T(com.example.OrderStatus).SHIPPED")
public void onOrderShipped(OrderStatusChangedEvent event) {
System.out.println("订单已发货: " + event.getOrderId());
}

@EventListener(condition = "#event.newStatus == T(com.example.OrderStatus).DELIVERED")
public void onOrderDelivered(OrderStatusChangedEvent event) {
System.out.println("订单已送达: " + event.getOrderId());
}
}

小结

本章介绍了 Spring 事件机制:

  1. 核心概念:事件、发布者、监听器
  2. 自定义事件:继承 ApplicationEvent
  3. 发布事件:ApplicationEventPublisher
  4. 监听事件:@EventListener、ApplicationListener
  5. 异步事件:@Async 注解
  6. 事务绑定事件:@TransactionalEventListener
  7. 内置事件:ContextRefreshedEvent 等
  8. 实际应用:用户注册、订单状态变更等场景

Spring 事件机制实现了组件间的松耦合通信,是构建可扩展应用的重要工具。