观察者模式实战:Spring Boot 3.x 实现订单状态变更通知(邮件+日志)
·
Spring Boot 3.x 实战观察者模式:构建订单状态变更的多渠道通知系统
1. 观察者模式在微服务架构中的价值
电商平台的订单状态变更是个典型的事件驱动场景。当用户完成支付后,系统需要同时触发邮件通知、短信提醒、日志记录、库存更新等多个操作。如果采用传统的同步调用方式,代码会陷入"面条式"的耦合:
// 反例:紧耦合的订单服务
public class OrderService {
public void processPayment(Order order) {
// 支付逻辑...
emailService.sendPaymentSuccess(order); // 同步阻塞
logService.recordPayment(order); // 同步阻塞
inventoryService.updateStock(order); // 同步阻塞
// 更多依赖调用...
}
}
观察者模式通过解耦事件发布者与订阅者,提供了更优雅的解决方案。Spring框架内置的 ApplicationEvent 机制正是该模式的经典实现,具有三大核心优势:
- 松耦合架构 :订单服务无需知晓具体有哪些监听器
- 异步处理能力 :通过
@Async实现非阻塞事件处理 - 动态扩展性 :新增监听器无需修改原有代码
2. Spring事件机制核心组件
2.1 事件定义
首先创建自定义事件类,继承 ApplicationEvent 并携带订单数据:
public class OrderPaymentEvent extends ApplicationEvent {
private final Order order;
public OrderPaymentEvent(Object source, Order order) {
super(source);
this.order = order;
}
public Order getOrder() {
return order;
}
}
2.2 事件发布
在订单服务中使用 ApplicationEventPublisher 发布事件:
@Service
@RequiredArgsConstructor
public class OrderService {
private final ApplicationEventPublisher eventPublisher;
public void confirmPayment(Order order) {
// 支付确认逻辑...
eventPublisher.publishEvent(new OrderPaymentEvent(this, order));
}
}
2.3 事件监听
通过 @EventListener 注解创建监听器:
@Service
@Slf4j
public class OrderPaymentListener {
@EventListener
public void handlePaymentSuccess(OrderPaymentEvent event) {
Order order = event.getOrder();
log.info("订单支付成功监听: 订单ID={}", order.getId());
}
}
3. 构建多渠道通知系统
3.1 邮件通知服务
实现带HTML模板的邮件发送:
@Service
@RequiredArgsConstructor
public class EmailNotificationService {
private final JavaMailSender mailSender;
private final ThymeleafTemplateEngine templateEngine;
@Async
@EventListener
public void sendPaymentEmail(OrderPaymentEvent event) {
Order order = event.getOrder();
Context context = new Context();
context.setVariable("order", order);
String htmlContent = templateEngine.process("payment-success", context);
MimeMessage message = mailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(message, true);
helper.setTo(order.getCustomerEmail());
helper.setSubject("您的订单支付成功");
helper.setText(htmlContent, true);
mailSender.send(message);
}
}
提示:使用
@Async需要主类添加@EnableAsync注解,并配置线程池
3.2 审计日志服务
记录订单状态变更的完整审计轨迹:
@Service
@RequiredArgsConstructor
public class AuditLogService {
private final AuditLogRepository logRepository;
@TransactionalEventListener(phase = AFTER_COMMIT)
public void logPaymentEvent(OrderPaymentEvent event) {
Order order = event.getOrder();
AuditLog log = AuditLog.builder()
.eventType("PAYMENT_SUCCESS")
.entityType("ORDER")
.entityId(order.getId())
.operator(order.getCustomerId())
.detail(JsonUtils.toJson(order))
.build();
logRepository.save(log);
}
}
关键参数对比:
| 监听器类型 | 触发时机 | 适用场景 |
|---|---|---|
@EventListener |
事件发布后立即执行 | 普通业务逻辑 |
@TransactionalEventListener |
事务提交后执行 | 需要事务保证的操作 |
3.3 异步配置优化
默认的SimpleAsyncTaskExecutor不适合生产环境,建议配置线程池:
@Configuration
@EnableAsync
public class AsyncConfig implements AsyncConfigurer {
@Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(5);
executor.setMaxPoolSize(10);
executor.setQueueCapacity(100);
executor.setThreadNamePrefix("Async-Event-");
executor.initialize();
return executor;
}
}
4. 高级应用与性能优化
4.1 条件化事件监听
通过SpEL表达式实现条件过滤:
@EventListener(condition = "#event.order.amount > 1000")
public void handleLargeOrder(OrderPaymentEvent event) {
// 仅处理金额大于1000的订单
}
4.2 事件处理顺序控制
使用 @Order 注解指定监听器执行顺序:
@EventListener
@Order(Ordered.HIGHEST_PRECEDENCE)
public void validatePayment(OrderPaymentEvent event) {
// 最先执行的校验逻辑
}
4.3 错误处理机制
自定义异常处理器保证事件处理健壮性:
@Configuration
public class EventErrorHandlingConfig {
@Bean
public ApplicationListener<AsyncUncaughtExceptionEvent> asyncExceptionHandler() {
return event -> {
log.error("异步事件处理异常", event.getThrowable());
// 发送告警通知等
};
}
}
5. 生产环境最佳实践
-
事件设计原则 :
- 保持事件轻量化,避免携带大对象
- 定义明确的事件命名规范(如
OrderPaymentEvent) - 考虑事件版本兼容性
-
监控指标 :
@EventListener public void monitorEventProcessing(OrderPaymentEvent event) { Metrics.counter("order.payment.events").increment(); // 更多监控指标... } -
性能优化技巧 :
- 对高频事件采用批量处理
- 为不同业务事件分配独立线程池
- 实现事件背压机制防止系统过载
实际项目中,我们曾遇到订单高峰期的性能瓶颈。通过将同步事件改为异步处理,并引入事件批处理机制,系统吞吐量提升了3倍。关键优化点在于合理控制线程池参数和队列容量,避免内存溢出。
更多推荐




所有评论(0)