一、源码分析 Spring5.3.2
1、先看一哈发布事件demo主要类
//main启动类
public class Main {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext("com.leon");
System.out.println(Thread.currentThread().getName() + "发布了TestEvent事件");
//发布TestEvent事件
context.publishEvent(new TestEvent(new TestView()));
}
}
//自定义事件类
public class TestEvent extends ApplicationEvent {
public TestEvent(Object source) {
super(source);
}
}
//一个数据视图类
@Data
public class TestView {
private String name = "leon";
private Integer age = 24;
}
//事件监听者
@Component
public class Subscriber implements ApplicationListener<TestEvent> {
@Override
public void onApplicationEvent(TestEvent event) {
System.out.println(Thread.currentThread().getName() + "监听到了TestEvent事件");
Object source = event.getSource();
System.out.println(source);
}
}
2、开始源码分析
从context.publishEvent()发布事件开始
//org.springframework.context.support.AbstractApplicationContext#publishEvent(org.springframework.context.ApplicationEvent)
public void publishEvent(ApplicationEvent event) {
publishEvent(event, null);
}
//org.springframework.context.support.AbstractApplicationContext#publishEvent(java.lang.Object)
public void publishEvent(Object event) {
publishEvent(event, null);
}
我们阔以看到有两个发布事件的方法,一个是发布ApplicationEvent参数的方法,一个是发布一个Object参数的方法,继续往下看publishEvent方法
//org.springframework.context.support.AbstractApplicationContext#publishEvent(java.lang.Object, org.springframework.core.ResolvableType)
/**
* @Param event 上面publishEvent方法的入参,可能是ApplicationEvent的实例,也可能是一个Object实例
* @Param eventType 上面publishEvent方法的入参类型元数据的一个包装类
**/
protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
Assert.notNull(event, "Event must not be null");
ApplicationEvent applicationEvent;
//如果入参是事件实例
if (event instanceof ApplicationEvent) {
applicationEvent = (ApplicationEvent) event;
}
else {
//如果入参不是事件实例,就把该入参封装成一个PayloadApplicationEvent事件实例
applicationEvent = new PayloadApplicationEvent<>(this, event);
if (eventType == null) {
eventType = ((PayloadApplicationEvent<?>) applicationEvent).getResolvableType();
}
}
if (this.earlyApplicationEvents != null) {
this.earlyApplicationEvents.add(applicationEvent);
}
else {
//得到事件广播器,把当前事件广播
getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
}
if (this.parent != null) {
//把事件传播给当前ApplicationContext的父类ApplicationContext发布,即把当前事件广播给父类ApplicationContext所有监听器
if (this.parent instanceof AbstractApplicationContext) {
((AbstractApplicationContext) this.parent).publishEvent(event, eventType);
}
else {
this.parent.publishEvent(event);
}
}
}
上面代码总结一哈就是,判断广播的对象是不是一个ApplicationEvent事件实例,如果是就把该事件发布,不是的话就把该对象封装成一个PayloadApplicationEvent事件实例对象再发布,最后还要把该广播对象传到父类上下文去发布,我们现在继续看事件广播器的multicastEvent()广播事件方法
//org.springframework.context.event.SimpleApplicationEventMulticaster#multicastEvent(org.springframework.context.ApplicationEvent, org.springframework.core.ResolvableType)
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
//得到当前事件广播器的执行器
Executor executor = getTaskExecutor();
//遍历匹配当前事件所有的监听器(ApplicationListener)
for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
//如果执行器不为空,就用执行器调用监听器onApplicationEvent(代码)
if (executor != null) {
executor.execute(() -> invokeListener(listener, event));
}
else {
//如果执行器为空,就用发布者当前线程调用监听器onApplicationEvent(代码)
invokeListener(listener, event);
}
}
}
上面代码很明显就知道,如果当前事件广播器(ApplicationEventMulticaster)里有执行器就用执行器执行监听器代码(异步),如果没得就用当前事件的发布者线程进行调用(同步),下面我们继续看事件广播器的getTaskExecutor()得到执行器方法能得到执行器不
//org.springframework.context.event.SimpleApplicationEventMulticaster#taskExecutor
private Executor taskExecutor;
//org.springframework.context.event.SimpleApplicationEventMulticaster#getTaskExecutor
protected Executor getTaskExecutor() {
return this.taskExecutor;
}
SimpleApplicationEventMulticaster中没看到taskExecutor设值得地方,debug调试也为空,说明其他地方也没设置值,所以Spring事件默认是发布者线程进行调用,那么问题来了,如果我们要用执行器进行监听器调用该如何办呢,其实我们看了刚才的代码很明显了,我们只需要设置一个执行器到事件广播器中就行了,所以我们找到事件广播器SimpleApplicationEventMulticaster初始化的地方看哈代码
//org.springframework.context.support.AbstractApplicationContext#APPLICATION_EVENT_MULTICASTER_BEAN_NAME
public static final String APPLICATION_EVENT_MULTICASTER_BEAN_NAME = "applicationEventMulticaster";
//org.springframework.context.support.AbstractApplicationContext#initApplicationEventMulticaster
protected void initApplicationEventMulticaster() {
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
/**
* 如果容器中有实例名叫"applicationEventMulticaster"的ApplicationEventMulticaster事件广播器实例,
* 就把该事件广播器赋值到AbstractApplicationContext上下文中applicationEventMulticaster变量,这里
* 应该是为了某些人需要自定义ApplicationEventMulticaster事件广播器做预留。
**/
if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
this.applicationEventMulticaster =
beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
if (logger.isTraceEnabled()) {
logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
}
}
else {
/**
* 说明容器中没有自定义的ApplicationEventMulticaster事件广播器,就把Spring默认的SimpleApplicationEventMulticaster
* 事件广播器复制给AbstractApplicationContext上下文中applicationEventMulticaster变量, 并注册到容器中。
**/
//创建默认的事件广播器
this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
//把该实例注册到容器中
beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
if (logger.isTraceEnabled()) {
logger.trace("No '" + APPLICATION_EVENT_MULTICASTER_BEAN_NAME + "' bean, using " +
"[" + this.applicationEventMulticaster.getClass().getSimpleName() + "]");
}
}
}
通过上述代码,我们阔以知道Spring默认是把SimpleApplicationEventMulticaster事件赋值给上下文并把他注入到容器中,所以我们只需要从容器中取出实例名叫"applicationEventMulticaster"的事件广播器实例,并把自定义的Executor执行器设置进事件广播器中即可
二、事件监听器调用者总结
通过上述分析,我们阔以知道如下:
- Spring事件监听器(ApplicationListener)onApplicationEvent方法默认是发布者线程调用(同步);
- 如果想用执行器(Executor)进行调用的(异步),需要将默认的SimpleApplicationEventMulticaster事件广播器中的执行器设置一个执行器,示例代码如下:
示例一:
@Component
public class EventThreadPoolConfig implements ApplicationContextAware {
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
SimpleApplicationEventMulticaster applicationEventMulticaster = applicationContext.getBean(AbstractApplicationContext.APPLICATION_EVENT_MULTICASTER_BEAN_NAME, SimpleApplicationEventMulticaster.class);
Executor taskExecutor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
applicationEventMulticaster.setTaskExecutor(taskExecutor);
}
}
示例二:
@Configuration
public class EventExecutorConfig {
@Bean("taskExecutor")
public Executor initExecutor() {
ThreadFactory namedThreadFactory = new ThreadFactoryBuilder()
.setNameFormat("taskExecutor-%d").build();
Executor taskExecutor = new ThreadPoolExecutor(5, 10,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(1024), namedThreadFactory, new ThreadPoolExecutor.AbortPolicy());
return taskExecutor;
}
@Bean(AbstractApplicationContext.APPLICATION_EVENT_MULTICASTER_BEAN_NAME)
public ApplicationEventMulticaster initEventMulticaster(@Qualifier("taskExecutor") Executor taskExecutor) {
SimpleApplicationEventMulticaster simpleApplicationEventMulticaster = new SimpleApplicationEventMulticaster();
simpleApplicationEventMulticaster.setTaskExecutor(taskExecutor);
return simpleApplicationEventMulticaster;
}
}