文章目录
- Spring默认的事件广播器 SimpleApplicationEventMulticaster#multicastEvent
- 获取executor
- 设置executor
- 得出操作步骤
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;
("com.artisan.eventlistener2")
public class ArtisanConfig {
(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;
public class ArtisanListenerByAnno {
(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");
}
}
【结果】
如果我们把配置类中的
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 赋上自定义的线程池即可,这个时候就能实现异步事件处理了 .
得出操作步骤
所以,可以这么配置
方式一
("com.artisan.eventlistener2")
public class ArtisanConfig {
(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;
("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;
}
("unchecked")
public void multicastEvent(final ApplicationEvent event) {
}
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