Spring的自定义事件广播机制, 能非常好的将我们的业务代码解耦, 提升代码的可读性, 学习一下, 没坏处
1. 最基础的使用
-
自定义事件类
@Getterpublic class MyEvent extends ApplicationEvent { //也可以不继承public LiveRoomTimeChangeEvent(Object source) {super(source);}}
定义事件监听器
@Componentpublic class MyEventListener {@EventListenerpublic void consumeEvent(MyEvent myEvent) {//doSomething}}
-
广播事件
@Componentpublic class A {@Autowiredprivate ApplicationContext applicationContext;public void methodA() {//广播事件applicationContext.publishEvent(new MyEvent(this));}}
2. 通过实现接口的方式注册事件监听器
在前面的例子中, 我们使用了
@EventListener注解的方式声明监听器
其实Spring还提供了另一种方式实现监听器
@Componentpublic class MyEventListener2 implements ApplicationListener<MyEvent> {@Overridepublic void onApplicationEvent(MyEvent event) {System.out.println(Thread.currentThread().getName());}}
这样写的优势是, 用泛型规范了代码, 可以在编译时发现一些错误
3. 异步消费
默认情况是不会异步消费事件的, 我们需要提前配置才能让事件异步的进行消费
3.1 默认情况同步消费
默认消费事件与广播事件, 是在同一个线程完成的
- 看下图的调试结果

-
3.2 实现异步消费
org.springframework.context.event.SimpleApplicationEventMulticaster#multicastEvent(org.springframework.context.ApplicationEvent, org.springframework.core.ResolvableType)- 通过观察源码可以看到 必须提前设置
taskExecutor才能异步地消费事件

- 我们这需要下面几件事
- 自定义事件分发器
ApplicationEventMulticaster - 自定义线程池
- 将自定义线程池设置到事件分发器中
@Configurationpublic class AsyncEventConfig implements BeanPostProcessor {@Bean("applicationEventMulticaster") //注意必须是这个名字public ApplicationEventMulticaster applicationEventMulticaster() { //手动创建事件广播器SimpleApplicationEventMulticaster result = new SimpleApplicationEventMulticaster();result.setTaskExecutor(this.eventExecutor().getObject());//设置异步线程池return result;}@Beanpublic ThreadPoolExecutorFactoryBean eventExecutor() {//创建线程池ThreadPoolExecutorFactoryBean eventExecutor = new ThreadPoolExecutorFactoryBean();eventExecutor.setThreadNamePrefix("eventExecutor-");eventExecutor.setCorePoolSize(3);return eventExecutor;}}
- 打印线程看看效果

使用这种方法会有一个问题, 就是所有的事件全部变成异步的了, 如果希望同步的消费反而不行了
而且所有的事件, 全在一个线程池中, 这样就没有优先级的区分, 不是非常完美
3.3 使用@Async实现异步调用
- 启用Spring的Async功能
并注册多个线程池
@EnableAsync@Configurationpublic class AsyncConfig {//这里可以初始化多个线程池, 让@Async执行的时候指定线程池@Bean("一号线程池")public ThreadPoolExecutorFactoryBean eventExecutor1() {ThreadPoolExecutorFactoryBean eventExecutor = new ThreadPoolExecutorFactoryBean();eventExecutor.setThreadNamePrefix("一号线程池-");eventExecutor.setCorePoolSize(3);return eventExecutor;}@Bean("二号线程池")public ThreadPoolExecutorFactoryBean eventExecutor2() {ThreadPoolExecutorFactoryBean eventExecutor = new ThreadPoolExecutorFactoryBean();eventExecutor.setThreadNamePrefix("二号线程池-");eventExecutor.setCorePoolSize(3);return eventExecutor;}}
注册监听器的时候使用 @Async
并指定执行的线程池
@Componentpublic class MyEventListener1 {@Async("一号线程池")@EventListenerpublic void consumeEvent(MyEvent myEvent) {System.out.println(Thread.currentThread().getName());}}@Componentpublic class MyEventListener2 implements ApplicationListener<MyEvent> {@Async("二号线程池")@Overridepublic void onApplicationEvent(MyEvent event) {System.out.println(Thread.currentThread().getName());}}
看看推送事件之后的执行结果

这里注意一下, 如果使用 @Async 的方式, 就不要自己注册 ApplicationEventMulticaster 了, 浪费资源
