1. ApplicationEventPublisher 同步与异步处理
1.1 默认同步行为
ApplicationEventPublisher 默认采用同步处理机制:
@Service
public class OrderService {
@Autowired
private ApplicationEventPublisher publisher;
@Transactional
public void createOrder() {
System.out.println("开始发布订单创建事件...");
// 同步发布事件 - 会阻塞直到所有监听器执行完成
publisher.publishEvent(new OrderCreatedEvent("ORDER-123"));
// 这行代码会等待所有监听器执行完后才会执行
System.out.println("事件发布完成,继续主流程。");
}
}
@Component
public class OrderEventListener {
@EventListener
public void handleOrderCreated(OrderCreatedEvent event) {
// 模拟耗时操作 - 会阻塞主线程
Thread.sleep(2000);
System.out.println("监听器处理完毕");
}
}
同步执行输出:
[http-nio-8080-exec-1] 开始发布订单创建事件...
[http-nio-8080-exec-1] 监听器处理完毕
[http-nio-8080-exec-1] 事件发布完成,继续主流程。
1.2 异步处理方案
方案一:使用 @Async 注解(推荐)
@SpringBootApplication
@EnableAsync // 开启异步支持
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
@Component
public class OrderEventListener {
@Async // 标记为异步方法
@EventListener
public void handleOrderCreated(OrderCreatedEvent event) {
System.out.println("[" + Thread.currentThread().getName() + "] 异步处理事件");
Thread.sleep(2000);
System.out.println("异步处理完成");
}
}
异步执行输出:
[http-nio-8080-exec-1] 开始发布订单创建事件...
[http-nio-8080-exec-1] 事件发布完成,继续主流程。
[task-1] 异步处理事件
[task-1] 异步处理完成
方案二:自定义线程池
@Configuration
public class AsyncConfig {
@Bean("customEventExecutor")
public Executor customEventExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(5);
executor.setMaxPoolSize(10);
executor.setQueueCapacity(100);
executor.setThreadNamePrefix("custom-event-");
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.initialize();
return executor;
}
}
@Component
public class ManualAsyncEventPublisher {
@Autowired
@Qualifier("customEventExecutor")
private Executor customEventExecutor;
@Autowired
private ApplicationEventPublisher eventPublisher;
public void publishEventAsync(Object event) {
customEventExecutor.execute(() -> {
eventPublisher.publishEvent(event);
});
}
}
方案三:全局异步配置
@Configuration
public class AsyncEventConfig {
@Bean
public ApplicationEventMulticaster applicationEventMulticaster() {
SimpleApplicationEventMulticaster eventMulticaster = new SimpleApplicationEventMulticaster();
eventMulticaster.setTaskExecutor(asyncTaskExecutor()); // 设置全局异步
return eventMulticaster;
}
@Bean
public Executor asyncTaskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(5);
executor.setMaxPoolSize(10);
executor.setQueueCapacity(25);
executor.setThreadNamePrefix("async-event-");
executor.initialize();
return executor;
}
}
2. 为什么即使同步也要使用事件驱动
2.1 架构解耦对比
紧耦合方案(直接调用):
@Service
public class OrderService {
@Autowired private EmailService emailService;
@Autowired private PointsService pointsService;
@Autowired private InventoryService inventoryService;
@Autowired private AuditService auditService;
@Transactional
public void createOrder(Order order) {
// 核心业务逻辑
orderRepository.save(order);
// 各种后续处理直接耦合在一起
emailService.sendOrderConfirmation(order);
pointsService.addPoints(order.getUserId(), order.getAmount());
inventoryService.updateStock(order.getItems());
auditService.logOrderCreation(order);
// 新增功能需要修改这里
notificationService.pushNotification(order);
}
}
松耦合方案(事件驱动):
@Service
public class OrderService {
@Autowired
private ApplicationEventPublisher eventPublisher;
@Transactional
public void createOrder(Order order) {
// 只关注核心业务逻辑
orderRepository.save(order);
// 发布事件,不关心谁来处理
eventPublisher.publishEvent(new OrderCreatedEvent(order));
}
}
// 各个处理逻辑独立存在
@Component
public class EmailService {
@EventListener
public void sendOrderConfirmation(OrderCreatedEvent event) {
// 发送邮件
}
}
@Component
public class PointsService {
@EventListener
public void addPoints(OrderCreatedEvent event) {
// 增加积分
}
}
2.2 设计优势
| 方面 | 直接调用 | 事件驱动 |
|---|---|---|
| 耦合度 | 紧耦合,修改影响大 | 松耦合,易于修改 |
| 单一职责 | 一个方法多重职责 | 单一职责,清晰明确 |
| 可测试性 | 测试复杂,依赖多 | 测试简单,可独立测试 |
| 可扩展性 | 修改原有代码 | 新增监听器,不修改原有代码 |
| 团队协作 | 容易冲突 | 并行开发,减少冲突 |
3. ApplicationEventPublisher 异步 vs 消息队列
3.1 架构层级对比
| 维度 | ApplicationEventPublisher (异步) | 消息队列 (MQ) |
|---|---|---|
| 架构层级 | 应用内事件总线 | 跨应用的消息中间件 |
| 通信范围 | 单个JVM进程内 | 跨进程、跨服务、跨网络 |
| 部署模式 | 单体或集群内独立 | 集中式消息代理 |
| 可靠性 | 低(内存级) | 高(持久化) |
| 性能 | 高(无网络开销) | 中(网络IO) |
3.2 可靠性对比
ApplicationEventPublisher(内存事件,可靠性低):
@Component
public class OrderService {
@Async
@EventListener
public void handleOrderCreated(OrderCreatedEvent event) {
// ❌ 应用重启时,正在处理的事件会丢失
// ❌ 事件只在内存中,没有持久化
emailService.sendConfirmation(event.getOrder());
}
}
消息队列(持久化保证,可靠性高):
@Component
public class MessageQueueConsumer {
@RabbitListener(queues = "order.created.queue")
public void consumeOrderCreated(OrderCreatedEvent event) {
try {
emailService.sendConfirmation(event.getOrder());
// ✅ 手动确认,确保处理成功后才删除消息
channel.basicAck(deliveryTag, false);
} catch (Exception e) {
// ✅ 处理失败,消息重新入队或进入死信队列
channel.basicNack(deliveryTag, false, true);
}
}
}
3.3 分布式场景对比
ApplicationEventPublisher(集群问题):
@Service
public class OrderService {
public void createOrder(Order order) {
orderRepository.save(order);
eventPublisher.publishEvent(new OrderCreatedEvent(order));
// ❌ 在集群中,事件只会在当前节点处理
// ❌ 其他节点的监听器收不到这个事件
}
}
消息队列(集群支持):
@Service
public class OrderService {
@Autowired
private RabbitTemplate rabbitTemplate;
public void createOrder(Order order) {
orderRepository.save(order);
rabbitTemplate.convertAndSend("order.exchange", "order.created", order);
// ✅ 所有消费节点都能收到消息
// ✅ 天然支持集群消费
}
}
@Component
public class OrderConsumer {
@RabbitListener(queues = "order.queue")
public void processOrder(Order order) {
// ✅ 多个实例同时消费,自动负载均衡
// ✅ 同一消息只会被一个消费者处理
}
}
3.4 事务一致性对比
ApplicationEventPublisher 事务处理:
@Service
public class OrderService {
@Transactional
public void createOrder(Order order) {
orderRepository.save(order); // 数据库事务
eventPublisher.publishEvent(new OrderCreatedEvent(order));
// ❌ 事件发布在事务提交前,可能出现:
// 1. 事务回滚但事件已发布
// 2. 事务提交但事件发布失败
}
}
// 解决方案:使用 @TransactionalEventListener
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
public void handleAfterCommit(OrderCreatedEvent event) {
// ✅ 只在事务提交成功后执行
}
消息队列事务方案:
@Service
public class OrderService {
@Transactional
public void createOrder(Order order) {
orderRepository.save(order);
// 本地事务表方案
eventRepository.save(new DomainEvent(order.getId(), "ORDER_CREATED"));
}
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
public void publishToMQ(OrderCreatedEvent event) {
// 从事务表中取出事件发送到MQ
rabbitTemplate.convertAndSend("order.exchange", "order.created", event);
eventRepository.delete(event.getId()); // 清理已发送事件
}
}
4. 适用场景指南
4.1 适合 ApplicationEventPublisher 的场景
// 场景1:应用内业务逻辑解耦
@Component
public class OrderStatusListener {
@Async
@EventListener
public void handleOrderPaid(OrderPaidEvent event) {
// 更新订单状态、清理缓存等应用内操作
cacheService.evict("order::" + event.getOrderId());
orderStatusService.updateStatus(event.getOrderId(), OrderStatus.PAID);
}
}
// 场景2:可丢失的轻量级事件
@Component
public class UserBehaviorListener {
@Async
@EventListener
public void trackUserAction(UserActionEvent event) {
// 用户行为追踪,丢失一些数据可以接受
analyticsService.track(event.getUserId(), event.getAction());
}
}
// 场景3:开发测试环境
@Component
public class DevEnvironmentListener {
@EventListener
public void logForDebug(ApplicationEvent event) {
// 开发环境的调试日志,不需要高可靠性
log.debug("Event published: {}", event);
}
}
4.2 适合消息队列的场景
// 场景1:跨服务通信
@Service
public class CrossServiceCommunication {
public void placeOrder(Order order) {
orderService.create(order);
// 通知其他微服务
rabbitTemplate.convertAndSend("order.exchange", "order.created", order);
}
}
// 场景2:高可靠性业务
@Component
public class PaymentResultConsumer {
@RabbitListener(queues = "payment.result.queue")
public void handlePaymentResult(PaymentResult result) {
// 支付结果处理,必须保证不丢失
if (result.isSuccess()) {
orderService.confirmOrder(result.getOrderId());
} else {
orderService.cancelOrder(result.getOrderId());
}
}
}
// 场景3:流量削峰
@Component
public class ImageProcessingConsumer {
@RabbitListener(queues = "image.process.queue")
public void processImage(ImageProcessTask task) {
// 图片处理,耗时操作,需要缓冲
imageService.resize(task.getImageId(), task.getSizes());
imageService.watermark(task.getImageId(), task.getWatermark());
}
}
5. 混合架构方案
在实际项目中,经常采用混合方案发挥各自优势:
@Service
public class OrderService {
@Transactional
public void createOrder(Order order) {
// 1. 核心业务逻辑
orderRepository.save(order);
// 2. 应用内事件(异步)- 处理应用内逻辑
eventPublisher.publishEvent(new OrderCreatedEvent(order));
// 3. 跨服务事件(消息队列)- 通知其他微服务
rabbitTemplate.convertAndSend("order.exchange",
"order.created", new OrderCreatedMessage(order));
}
}
// 应用内监听器 - 处理内部关注点
@Component
public class InternalEventListener {
@Async
@EventListener
public void handleInternalLogic(OrderCreatedEvent event) {
// 应用内逻辑:缓存、监控、日志等
cacheService.warmUp(order);
metricService.increment("order.created");
log.info("Order created: {}", event.getOrderId());
}
}
// 跨服务消费者 - 处理外部集成
@Component
public class ExternalServiceConsumer {
@RabbitListener(queues = "order.created.queue")
public void notifyExternalSystems(OrderCreatedMessage message) {
// 通知库存服务
inventoryService.reserveStock(message.getItems());
// 通知推荐服务
recommendationService.recordPurchase(message.getUserId());
// 通知风控服务
riskControlService.analyzeOrder(message);
}
}
6. 全面对比总结
| 特性 | ApplicationEventPublisher (异步) | 消息队列 |
|---|---|---|
| 可靠性 | 低(内存级,重启丢失) | 高(磁盘持久化) |
| 性能 | 高(无网络IO) | 中(有网络开销) |
| 扩展性 | 单应用内 | 跨应用、跨服务 |
| 复杂度 | 低(Spring内置) | 高(需要中间件) |
| 事务支持 | 有限(@TransactionalEventListener) | 强(事务消息、本地消息表) |
| 部署依赖 | 无(框架内置) | 需要部署维护MQ |
| 适用场景 | 应用内解耦、可丢失事件 | 跨服务通信、高可靠性 |
| 成本 | 低(无额外基础设施) | 中高(硬件+运维) |
7. 最佳实践建议
7.1 选择策略
选择 ApplicationEventPublisher 当:
- 业务逻辑在单个应用内
- 事件可丢失或影响不大
- 开发效率优先,快速迭代
- 团队技术栈统一,无分布式需求
选择消息队列当:
- 需要跨微服务通信业务
- 要求高可靠性,不能丢失消息
- 需要流量削峰、异步缓冲系统
- 需要水平扩展
7.2 性能优化建议
ApplicationEventPublisher 优化:
@Configuration
public class OptimizedAsyncConfig {
@Bean("optimizedEventExecutor")
public Executor optimizedEventExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
// 根据业务特点调整参数
executor.setCorePoolSize(Runtime.getRuntime().availableProcessors());
executor.setMaxPoolSize(Runtime.getRuntime().availableProcessors() * 2);
executor.setQueueCapacity(1000);
executor.setThreadNamePrefix("event-");
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.initialize();
return executor;
}
}
7.3 监控与运维
ApplicationEventPublisher 监控:
@Component
public class EventMonitoringAspect {
@Around("@annotation(org.springframework.scheduling.annotation.Async) && @annotation(org.springframework.context.event.EventListener)")
public Object monitorEventProcessing(ProceedingJoinPoint joinPoint) throws Throwable {
long startTime = System.currentTimeMillis();
try {
Object result = joinPoint.proceed();
log.info("Event processed successfully: {}, time: {}ms",
joinPoint.getSignature(), System.currentTimeMillis() - startTime);
return result;
} catch (Exception e) {
log.error("Event processing failed: {}", joinPoint.getSignature(), e);
throw e;
}
}
}
通过合理的架构选择和优化配置,可以充分发挥两种方案的优势,构建出既灵活又可靠的异步处理系统。
Spring事件异步与消息队列对比
856

被折叠的 条评论
为什么被折叠?



