首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >Spring5源码 - 11 Spring事件监听机制_源码篇

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

作者头像
小小工匠
发布2021-08-17 15:59:01
发布2021-08-17 15:59:01
5360
举报
文章被收录于专栏:小工匠聊架构小工匠聊架构


pre

Spring5源码 - 10 Spring事件监听机制_应用篇

观察者模式

说了应用,那我们来看下Spring的源码是如何实现这种事件监听机制的吧


事件监听机制的实现原理观察者模式

其实就是观察者模式


事件 ApplicationEvent

事件监听者 ApplicationEvent

相当于观察者模式中的观察者。监听器监听特定事件,并在内部定义了事件发生后的响应逻辑


事件发布者 ApplicationEventMulticaster (多播器)

相当于观察者模式中的被观察者/主题, 负责通知观察者 对外提供发布事件和增删事件监听器的接口,维护事件和事件监听器之间的映射关系,并在事件发生时负责通知相关监听器


工作流程

Spring事件机制是观察者模式的一种实现,但是除了发布者和监听者者两个角色之外,还有一个EventMultiCaster的角色负责把事件转发给监听者。

AnnotationConfigApplicationContext#publishEvent(ApplicationEvent event)将事件发送给了EventMultiCaster, 而后由EventMultiCaster注册着所有的Listener,然后根据事件类型决定转发给那个Listener。


源码解析

debug走起,

Spring在ApplicationContext接口的抽象实现类AbstractApplicationContext中完成了事件体系的搭建。

AbstractApplicationContext拥有一个applicationEventMulticaster成员变量,applicationEventMulticaster提供了容器监听器的注册表。

还是进入到refresh方法中

refresh() -----> 直接看 initApplicationEventMulticaster() -----------> registerListeners() ---------> finishRefresh() 进入 ----> publishEvent(new ContextRefreshedEvent(this))


初始化事件多播器 initApplicationEventMulticaster()

代码语言:javascript
复制
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 + "]");
			}
		}
	}​

一句话概括:我们可以在配置文件中为容器定义一个自定义的事件广播器,只要实现ApplicationEventMulticaster就可以了,Spring会通过 反射的机制将其注册成容器的事件广播器,如果没有找到配置的外部事件广播器,Spring默认使用 SimpleApplicationEventMulticaster作为事件广播器


注册事件到多播器中 registerListeners()

代码语言:javascript
复制
protected void registerListeners() {
		//去容器中把applicationListener 捞取出来注册到多播器上去(系统的)
		for (ApplicationListener<?> listener : getApplicationListeners()) {
			getApplicationEventMulticaster().addApplicationListener(listener);
		}

        //开发人员实现了ApplicationListener 的组件
		String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
		for (String listenerBeanName : listenerBeanNames) {
			getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
		}

	    //在这里之前,我们早期想发布的事件 由于没有多播器没有发布,在这里我们总算有了自己的多播器,可以在这里发布早期堆积的事件了. (早起发布事件,会自动发布,无需调用pubilish)
		Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
		this.earlyApplicationEvents = null;
		if (earlyEventsToProcess != null) {
			for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
				getApplicationEventMulticaster().multicastEvent(earlyEvent);
			}
		}
	}

一句话概括 : Spring根据反射机制,使用ListableBeanFactory的getBeansOfType方法,从BeanDefinitionRegistry中找出所有实现 org.springframework.context.ApplicationListener的Bean,将它们注册为容器的事件监听器,实际的操作就是将其添加到事件广播器所提供的监听器注册表中。


事件发布publishEvent(默认同步)

代码语言:javascript
复制
org.springframework.context.support.AbstractApplicationContext#publishEvent(java.lang.Object, org.springframework.core.ResolvableType)

进入 org.springframework.context.event.SimpleApplicationEventMulticaster#multicastEvent(org.springframework.context.ApplicationEvent, org.springframework.core.ResolvableType)

代码语言:javascript
复制
public void multicastEvent(final ApplicationEvent event, ResolvableType eventType) {
		ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
		//获取到所有的监听器
		for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
		    //看spring 容器中是否支持线程池 异步发送事件
			Executor executor = getTaskExecutor();
			if (executor != null) {
				executor.execute(new Runnable() {
					@Override
					public void run() {
					    
						invokeListener(listener, event);
					}
				});
			}
			else {  //同步发送事件
				invokeListener(listener, event);
			}
		}
	}	

支持异步,默认同步 。

遍历注册的每个监听器,并启动来调用每个监听器的onApplicationEvent方法。由于SimpleApplicationEventMulticastertaskExecutor的实现类是SyncTaskExecutor,因此,事件监听器对事件的处理,是同步进行的。

来看看

代码语言:javascript
复制
private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
		try {
		    //调用对于listener的onApplicationEvent事件
			listener.onApplicationEvent(event);
		}
		catch (ClassCastException ex) {
			String msg = ex.getMessage();
			if (msg == null || matchesClassCastMessage(msg, event.getClass())) {
				// Possibly a lambda-defined listener which we could not resolve the generic event type for
				// -> let's suppress the exception and just log a debug message.
				Log logger = LogFactory.getLog(getClass());
				if (logger.isDebugEnabled()) {
					logger.debug("Non-matching event type for listener: " + listener, ex);
				}
			}
			else {
				throw ex;
			}
		}
	}

就是调用 listener.onApplicationEvent(event);


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

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

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • pre
  • 事件监听机制的实现原理观察者模式
    • 事件 ApplicationEvent
    • 事件监听者 ApplicationEvent
    • 事件发布者 ApplicationEventMulticaster (多播器)
  • 工作流程
  • 源码解析
    • 初始化事件多播器 initApplicationEventMulticaster()
    • 注册事件到多播器中 registerListeners()
    • 事件发布publishEvent(默认同步)
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档