Spring ApplicationEventPublisher 异步处理与消息队列全面解析
1. ApplicationEventPublisher 同步与异步处理
1.1 默认同步行为
ApplicationEventPublisher 默认采用同步处理机制:
@Service
public class OrderService {@Autowiredprivate ApplicationEventPublisher publisher;@Transactionalpublic void createOrder() {System.out.println("开始发布订单创建事件...");// 同步发布事件 - 会阻塞直到所有监听器执行完成publisher.publishEvent(new OrderCreatedEvent("ORDER-123"));// 这行代码会等待所有监听器执行完后才会执行System.out.println("事件发布完成,继续主流程。");}
}@Component
public class OrderEventListener {@EventListenerpublic 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 // 标记为异步方法@EventListenerpublic 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;@Autowiredprivate ApplicationEventPublisher eventPublisher;public void publishEventAsync(Object event) {customEventExecutor.execute(() -> {eventPublisher.publishEvent(event);});}
}
方案三:全局异步配置
@Configuration
public