事件机制在一些大型项目中被经常使用,Spring 专门提供了一套事件机制的接口,满足了架构原则上的解耦。
ApplicationContext
通过 ApplicationEvent
类和 ApplicationListener
接口进行事件处理。
如果将实现 ApplicationListener
接口的 bean 注入到上下文中,则每次使用 ApplicationContext
发布 ApplicationEvent
时,都会通知该 bean。
本质上,这是标准的观察者设计模式
。
使用方法
- ApplicationContext,Spring 上下文对象,进行事件的发布,发布后通知监听器消费
- ApplicationEvent,事件对象,可以继承该类并定义消息体
- ApplicationListener,事件监听器顶层接口,实现该接口来消费消息
1. 定义消息体
/**
* @author shone
* @date 2022年07月28日 09:22
*/
public class TestEvent extends ApplicationEvent {
public TestEvent(Object source) {
super(source);
}
}
2. 定义监听器进行消息消费
/**
* @author shone
* @date 2022年07月28日 09:26
*/
@Slf4j
@Component
public class TestEventListener implements ApplicationListener<TestEvent> {
@Override
public void onApplicationEvent(TestEvent event) {
log.info("监听器处理事件:{}",event.getSource());
}
}
注意
需要自定义事件类继承 ApplicationEvent 类,因为 ApplicationEvent 是所有事件的基类,如果监听 ApplicationEvent 类型的任务,Spring 中存在其他的事件发布也会被监听到。
因此需要实现自定义的任务类,并在监听器中使用泛型执行监听任务类型,且发布时发布对应类型的任务。
3. 消息发布
@GetMapping("/test/pushEvent")
public String pushEvent() {
log.info("发布事件");
// 发布Spring事件通知
SpringUtil.getApplicationContext().publishEvent(new TestEvent("hello event!"));
return "hello";
}
4. 实现异步消费
定义线程池配置,并在监听器处理任务时指定使用的线程池,如果不指定 Spring 会生产默认类型,即会是同步处理任务。
/**
* @author shone
* @date 2022年07月28日 09:45
*/
@Slf4j
@Configuration
public class SpringConfiguration {
@Bean
public SimpleApplicationEventMulticaster applicationEventMulticaster(@Qualifier("defaultThreadPoolExecutor") ThreadPoolExecutor defaultThreadPoolExecutor) {
SimpleApplicationEventMulticaster simpleApplicationEventMulticaster = new SimpleApplicationEventMulticaster();
simpleApplicationEventMulticaster.setTaskExecutor(defaultThreadPoolExecutor);
return simpleApplicationEventMulticaster;
}
@Bean(name = "defaultThreadPoolExecutor", destroyMethod = "shutdown")
public ThreadPoolExecutor systemCheckPoolExecutorService() {
return new ThreadPoolExecutor(3, 10, 60, TimeUnit.SECONDS,
new LinkedBlockingQueue<Runnable>(10000),
(r, executor) -> log.error("system pool is full! "));
}
}