关于Spring事件监听器是发布者线程调用(同步)还是线程池调用(异步)的探究

一、源码分析 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执行器设置进事件广播器中即可

二、事件监听器调用者总结

通过上述分析,我们阔以知道如下:

  1. Spring事件监听器(ApplicationListener)onApplicationEvent方法默认是发布者线程调用(同步);
  2. 如果想用执行器(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;
    }

}
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值