首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Spring5源码 - 12 Spring事件监听机制_异步事件监听应用及源码解析

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

作者头像
小小工匠
发布2021-08-17 15:59:23
发布2021-08-17 15:59:23
1.1K00
代码可运行
举报
文章被收录于专栏:小工匠聊架构小工匠聊架构
运行总次数:0
代码可运行


Pre

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


实现原理

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

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


应用

配置类

代码语言:javascript
代码运行次数:0
运行
复制
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事件

代码语言:javascript
代码运行次数:0
运行
复制
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

代码语言:javascript
代码运行次数:0
运行
复制
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

代码语言:javascript
代码运行次数:0
运行
复制
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");
	}
}

【结果】

如果我们把配置类中的

代码语言:javascript
代码运行次数:0
运行
复制
@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")); 最终会调用到

代码语言:javascript
代码运行次数:0
运行
复制
org.springframework.context.event.SimpleApplicationEventMulticaster#multicastEvent(org.springframework.context.ApplicationEvent, org.springframework.core.ResolvableType)

获取executor

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

SimpleApplicationEventMulticaster的一个属性

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

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


设置executor

我们知道

代码语言:javascript
代码运行次数:0
运行
复制
org.springframework.context.support.AbstractApplicationContext#refresh

看看 initApplicationEventMulticaster

代码语言:javascript
代码运行次数:0
运行
复制
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 赋上自定义的线程池即可,这个时候就能实现异步事件处理了 .

得出操作步骤

所以,可以这么配置

方式一

代码语言:javascript
代码运行次数:0
运行
复制
@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 即可

代码语言:javascript
代码运行次数:0
运行
复制
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

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020/10/30 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Pre
  • 实现原理
  • 应用
    • 配置类
    • Event事件
    • 事件监听 EventListener
    • 发布事件 publishEvent
  • 源码解析 (反推)
    • Spring默认的事件广播器 SimpleApplicationEventMulticaster#multicastEvent
    • 获取executor
    • 设置executor
    • 得出操作步骤
      • 方式一
      • 方式二
  • 其他开启异步的方式
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档