概叙
科普文:软件架构Spring系列之【Spring事件机制ApplicationEvent】-CSDN博客
Spring事件(Spring Event)是基于观察者模式实现的轻量级消息通信机制,允许组件间通过发布-订阅模型解耦交互。
核心思想:基于发布-订阅模式实现组件间解耦,事件发布者(Publisher)与监听者(Listener)无需直接依赖,通过事件(Event)传递业务状态变更;事件发布者发布事件,事件监听器异步或同步监听并处理事件。
适用于订单状态变更、用户注册后异步操作等场景。
问题:Spring事件监听器能否捕获并处理其他模块发布的事件?
可以,Spring事件监听器能够捕获并处理其他模块发布的事件。
通过ApplicationEventMulticaster来实现。
原理(ApplicationEventMulticaster
)
Spring事件机制基于观察者模式,核心是ApplicationEvent
和ApplicationListener
。
事件发布者发布事件时,会将事件对象传递给ApplicationEventMulticaster
,它会遍历所有注册的监听器,并调用其处理方法。只要监听器被正确注册到Spring容器中,无论事件在哪个模块发布,监听器都能接收到并进行处理。
实现方式(ApplicationEventMulticaster
)
只要保证事件类在所有相关模块中可见(通常可以将事件类放在公共模块),并且监听器被Spring容器正确管理(使用@Component
等注解),那么Spring事件监听器就可以捕获并处理其他模块发布的事件,实现模块间的解耦通信。
1. 定义事件类
事件类需要继承ApplicationEvent
,可以在任意模块中定义。
// 在模块A中定义事件类
public class CustomEvent extends ApplicationEvent {
private String message;
public CustomEvent(Object source, String message) {
super(source);
this.message = message;
}
public String getMessage() {
return message;
}
}
2. 发布事件
在需要发布事件的模块中,注入ApplicationEventPublisher
,然后调用其publishEvent
方法发布事件。
// 在模块A的某个Service中发布事件
@Service
public class ModuleAService {
@Autowired
private ApplicationEventPublisher publisher;
public void doSomething() {
// 业务逻辑...
publisher.publishEvent(new CustomEvent(this, "这是来自模块A的消息"));
}
}
3. 监听事件
在其他模块中创建监听器类,实现ApplicationListener
接口或者使用@EventListener
注解来监听事件。
- 实现`ApplicationListener`接口
- 使用`@EventListener`注解
// 在模块B中创建监听器类
@Component
public class CustomEventListener implements ApplicationListener<CustomEvent> {
@Override
public void onApplicationEvent(CustomEvent event) {
System.out.println("模块B接收到事件消息: " + event.getMessage());
// 处理事件的逻辑...
}
}
// 在模块B中创建监听器类
@Component
public class CustomEventAnnotationListener {
@EventListener
public void handleCustomEvent(CustomEvent event) {
System.out.println("模块B通过注解接收到事件消息: " + event.getMessage());
// 处理事件的逻辑...
}
}
在Spring事件监听器中自定义线程池(spring事件异步处理补充)
科普文:软件架构Spring系列之【Spring事件机制ApplicationEvent】-CSDN博客
前面提到spring事件异步处理,这里对Spring事件监听器中自定义线程池做详细描述,主要是为异步处理的事件监听器配置专属线程池,避免使用默认的SimpleAsyncTaskExecutor
(每次创建新线程,性能差)。
为Spring事件监听器定制高性能的线程池,提升系统吞吐量和稳定性。
以下是具体步骤:
1. 定义自定义线程池
通过@Bean
创建一个ThreadPoolTaskExecutor
,并设置核心参数(如线程数、队列容量等):
@Configuration
public class AsyncConfig {
@Bean("customEventThreadPool") // 指定Bean名称,便于后续引用
public Executor customEventThreadPool() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(5); // 核心线程数
executor.setMaxPoolSize(10); // 最大线程数
executor.setQueueCapacity(100); // 任务队列容量
executor.setThreadNamePrefix("EventThread-"); // 线程名前缀(便于日志追踪)
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); // 拒绝策略
executor.initialize(); // 初始化线程池
return executor;
}
}
2. 在异步事件监听器中指定线程池
通过@Async
注解的value
或executor
属性,显式引用自定义线程池:
方式1:直接在方法上指定
@Component
public class OrderEventListener {
// 使用自定义线程池执行异步监听器
@Async("customEventThreadPool") // 关键:指定线程池Bean名称
@EventListener
public void handleOrderEvent(OrderCreatedEvent event) {
System.out.println("异步处理事件,线程: " + Thread.currentThread().getName());
// 业务逻辑...
}
}
方式2:全局配置默认线程池(可选)
若希望所有@Async
方法默认使用该线程池,可在配置类中设置:
@Configuration
@EnableAsync
public class AsyncConfig {
@Bean("customEventThreadPool")
public Executor customEventThreadPool() {
// ...同上线程池配置
}
@Bean
public AsyncConfigurer asyncConfigurer(@Qualifier("customEventThreadPool") Executor executor) {
return new AsyncConfigurer() {
@Override
public Executor getAsyncExecutor() {
return executor; // 全局默认线程池
}
};
}
}
3. 完整示例
事件定义与发布
// 事件类
public class OrderCreatedEvent extends ApplicationEvent {
public OrderCreatedEvent(Object source) {
super(source);
}
}
// 发布事件的Service
@Service
public class OrderService {
@Autowired
private ApplicationEventPublisher publisher;
@Transactional
public void createOrder() {
// 业务逻辑...
publisher.publishEvent(new OrderCreatedEvent(this));
}
}
异步监听器(使用自定义线程池)
@Component
public class OrderEventListener {
// 显式指定线程池
@Async("customEventThreadPool")
@EventListener
public void asyncHandleOrderEvent(OrderCreatedEvent event) {
System.out.println("异步处理订单事件,线程: " + Thread.currentThread().getName());
}
}
4. 关键注意事项
1. 线程池隔离:不同业务场景的事件监听器建议使用独立的线程池,避免互相影响(如订单事件和支付事件分离)。
2. 拒绝策略:当线程池满时,需合理配置RejectedExecutionHandler
(如CallerRunsPolicy
让调用线程直接执行,避免任务丢失)。
3. 监控与调优:通过日志或监控工具(如Prometheus)观察线程池状态(活跃线程数、队列堆积等),动态调整参数。
4. 与事务结合:若事件监听器需要事务支持,在方法上添加@Transactional
,但需注意事务与异步的线程切换问题(事务上下文可能丢失)。