Pre
Spring5源码 - 11 Spring事件监听机制_源码篇
实现原理
Spring提供的事件机制,默认是同步的。如果想要使用异步事件监听,可以自己实现ApplicationEventMulticaster接口,并在Spring容器中注册id为applicationEventMulticaster的Bean , 设置 executor 。
Spring会遍历所有的ApplicationListener, 如果 taskExecutor 不为空,这开启异步线程执行。
应用
配置类
package com.artisan.eventlistener2; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.event.ApplicationEventMulticaster; import org.springframework.context.event.SimpleApplicationEventMulticaster; import org.springframework.core.task.SimpleAsyncTaskExecutor; @Configuration @ComponentScan("com.artisan.eventlistener2") public class ArtisanConfig { @Bean(name = "applicationEventMulticaster") // Step1: id必须叫 applicationEventMulticaster public ApplicationEventMulticaster multicaster(){ // Step2:实例化SimpleApplicationEventMulticaster SimpleApplicationEventMulticaster simpleApplicationEventMulticaster = new SimpleApplicationEventMulticaster(); // Step3:设置TaskExecutor simpleApplicationEventMulticaster.setTaskExecutor(new SimpleAsyncTaskExecutor()); return simpleApplicationEventMulticaster ; } }
Event事件
package com.artisan.eventlistener2; import org.springframework.context.ApplicationEvent; public class ArtisanEvent extends ApplicationEvent { private String msg ; public ArtisanEvent(Object source) { super(source); } public ArtisanEvent(Object source,String msg) { super(source); this.msg = msg ; } public void print(){ System.out.println(Thread.currentThread().getName() + "-----" + msg); } }
事件监听 EventListener
package com.artisan.eventlistener2; import org.springframework.context.event.EventListener; import org.springframework.stereotype.Component; @Component public class ArtisanListenerByAnno { @EventListener(ArtisanEvent.class) public void onApplicationEvent(ArtisanEvent event) { System.out.println(Thread.currentThread().getName() + " EventListener 监听到ArtisanEvent....."); event.print(); } }
发布事件 publishEvent
package com.artisan.eventlistener2; import org.springframework.context.annotation.AnnotationConfigApplicationContext; public class ArtisanTest { public static void main(String[] args) { AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(ArtisanConfig.class); // 模拟发布事件 ac.publishEvent(new ArtisanEvent("xxxx","msg from artisanEvent")); System.out.println(Thread.currentThread().getName() + " over"); } }
【结果】
如果我们把配置类中的
@Bean(name = "applicationEventMulticaster") public ApplicationEventMulticaster multicaster(){ SimpleApplicationEventMulticaster simpleApplicationEventMulticaster = new SimpleApplicationEventMulticaster(); simpleApplicationEventMulticaster.setTaskExecutor(new SimpleAsyncTaskExecutor()); return simpleApplicationEventMulticaster ; }
移除掉,重新运行
就变成了默认的同步监听了。。。。
源码解析 (反推)
Spring默认的事件广播器 SimpleApplicationEventMulticaster#multicastEvent
我们分析一下 ac.publishEvent(new ArtisanEvent("xxxx","msg from artisanEvent")); 最终会调用到
org.springframework.context.event.SimpleApplicationEventMulticaster#multicastEvent(org.springframework.context.ApplicationEvent, org.springframework.core.ResolvableType)
获取executor
executor不为null则异步处理, 那看下executor = getTaskExecutor();
SimpleApplicationEventMulticaster的一个属性
那只要在实例化SimpleApplicationEventMulticaster的时候 set属性值就可以了哇。
所以现在的问题是什么时候给线程池属性赋值的问题?
设置executor
我们知道
org.springframework.context.support.AbstractApplicationContext#refresh
看看 initApplicationEventMulticaster
protected void initApplicationEventMulticaster() { ConfigurableListableBeanFactory beanFactory = getBeanFactory(); //判断IOC容器中包含applicationEventMulticaster 事件多播器的Bean的name if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) { //创建一个applicationEventMulticaster的bean放在IOC 容器中,bean的name 为applicationEventMulticaster this.applicationEventMulticaster =beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class); if (logger.isDebugEnabled()) { logger.debug("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]"); } } else { //容器中不包含一个beanName 为applicationEventMulticaster的多播器组件 //创建一个SimpleApplicationEventMulticaster 多播器 this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory); //注册到容器中 beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster); if (logger.isDebugEnabled()) { logger.debug("Unable to locate ApplicationEventMulticaster with name '" + APPLICATION_EVENT_MULTICASTER_BEAN_NAME + "': using default [" + this.applicationEventMulticaster + "]"); } } }
通过源码我们知道,Spring会先从容器中找 bean name 为 “applicationEventMulticaster” 的 bean,so问题就简单了,我们只要自定义个 bean name 为 applicationEventMulticaster 的 bean,并给其属性 taskExecutor 赋上自定义的线程池即可,这个时候就能实现异步事件处理了 .
得出操作步骤
所以,可以这么配置
方式一
@Configuration @ComponentScan("com.artisan.eventlistener2") public class ArtisanConfig { @Bean(name = "applicationEventMulticaster") public ApplicationEventMulticaster multicaster(){ SimpleApplicationEventMulticaster simpleApplicationEventMulticaster = new SimpleApplicationEventMulticaster(); simpleApplicationEventMulticaster.setTaskExecutor(new SimpleAsyncTaskExecutor()); return simpleApplicationEventMulticaster ; } }
方式二
或者写一个类实现 AbstractApplicationEventMulticaster ,仿照 SimpleApplicationEventMulticaster 即可
package com.artisan.eventlistener2; import org.springframework.context.ApplicationEvent; import org.springframework.context.ApplicationListener; import org.springframework.context.event.AbstractApplicationEventMulticaster; import org.springframework.core.ResolvableType; import org.springframework.core.task.SimpleAsyncTaskExecutor; import org.springframework.core.task.TaskExecutor; import org.springframework.stereotype.Component; import java.util.Iterator; @Component("applicationEventMulticaster") public class AsyncApplicationEventMulticaster extends AbstractApplicationEventMulticaster { private TaskExecutor taskExecutor = new SimpleAsyncTaskExecutor(); public void setTaskExecutor(TaskExecutor taskExecutor) { this.taskExecutor = (taskExecutor != null ? taskExecutor : new SimpleAsyncTaskExecutor()); } protected TaskExecutor getTaskExecutor() { return this.taskExecutor; } @Override @SuppressWarnings("unchecked") public void multicastEvent(final ApplicationEvent event) { } @Override public void multicastEvent(ApplicationEvent event, ResolvableType eventType) { for (Iterator<ApplicationListener<?>> it = getApplicationListeners().iterator(); it.hasNext();) { final ApplicationListener listener = it.next(); System.out.println("-----------自定义异步事件监听-----------"); getTaskExecutor().execute(() -> listener.onApplicationEvent(event)); } } }
其他开启异步的方式
@EnbaleAsyn + @Async