文章目录


Spring5源码 - 12 Spring事件监听机制_异步事件监听应用及源码解析_自定义


Pre

Spring5源码 - 11 Spring事件监听机制_源码篇

Spring5源码 - 12 Spring事件监听机制_异步事件监听应用及源码解析_自定义_02


实现原理

Spring提供的事件机制,默认是同步的。如果想要使用异步事件监听,可以自己实现ApplicationEventMulticaster接口,并在Spring容器中注册id为applicationEventMulticaster的Bean , 设置 executor 。

Spring会遍历所有的ApplicationListener, 如果 taskExecutor 不为空,这开启异步线程执行。

Spring5源码 - 12 Spring事件监听机制_异步事件监听应用及源码解析_事件监听_03


应用

配置类

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");
}
}

【结果】

Spring5源码 - 12 Spring事件监听机制_异步事件监听应用及源码解析_事件监听_04

如果我们把配置类中的

@Bean(name = "applicationEventMulticaster")
public ApplicationEventMulticaster multicaster(){
SimpleApplicationEventMulticaster simpleApplicationEventMulticaster = new SimpleApplicationEventMulticaster();
simpleApplicationEventMulticaster.setTaskExecutor(new SimpleAsyncTaskExecutor());
return simpleApplicationEventMulticaster ;
}

移除掉,重新运行

Spring5源码 - 12 Spring事件监听机制_异步事件监听应用及源码解析_spring_05

就变成了默认的同步监听了。。。。


源码解析 (反推)

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)

Spring5源码 - 12 Spring事件监听机制_异步事件监听应用及源码解析_spring_06


获取executor

executor不为null则异步处理, 那看下​​executor = getTaskExecutor();​

Spring5源码 - 12 Spring事件监听机制_异步事件监听应用及源码解析_自定义_07

SimpleApplicationEventMulticaster的一个属性

Spring5源码 - 12 Spring事件监听机制_异步事件监听应用及源码解析_异步事件监听_08

Spring5源码 - 12 Spring事件监听机制_异步事件监听应用及源码解析_自定义_09

那只要在实例化SimpleApplicationEventMulticaster的时候 set属性值就可以了哇。

所以现在的问题是什么时候给线程池属性赋值的问题?


设置executor

我们知道

org.springframework.context.support.AbstractApplicationContext#refresh

Spring5源码 - 12 Spring事件监听机制_异步事件监听应用及源码解析_异步事件监听_10

看看 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));
}
}
}

Spring5源码 - 12 Spring事件监听机制_异步事件监听应用及源码解析_自定义_11


其他开启异步的方式

@EnbaleAsyn + @Async

Spring5源码 - 12 Spring事件监听机制_异步事件监听应用及源码解析_异步事件监听_12