事件机制
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 提供了一些内置事件:
| 事件 | 触发时机 |
|---|---|
| ContextRefreshedEvent | ApplicationContext 初始化或刷新完成 |
| ContextStartedEvent | ApplicationContext 启动 |
| ContextStoppedEvent | ApplicationContext 停止 |
| ContextClosedEvent | ApplicationContext 关闭 |
| 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 事件机制:
- 核心概念:事件、发布者、监听器
- 自定义事件:继承 ApplicationEvent
- 发布事件:ApplicationEventPublisher
- 监听事件:@EventListener、ApplicationListener
- 异步事件:@Async 注解
- 事务绑定事件:@TransactionalEventListener
- 内置事件:ContextRefreshedEvent 等
- 实际应用:用户注册、订单状态变更等场景
Spring 事件机制实现了组件间的松耦合通信,是构建可扩展应用的重要工具。