死磕源码系列【ApplicationEventMulticaster接口及实现类源码解析】_艾米莉Emily的博客-程序员宝宝

技术标签: 【死磕spring源码】  

ApplicationEventMulticaster接口的实现类可以管理多个ApplicationListener监听器对象,并且发布事件到监听器;ApplicationEventMulticaster其实是ApplicationEventPublisher发布事件的代理类,通常作为SpringApplicationRunListener接口实现类EventPublishingRunListener的一个属性来使用;

类的结构图:

在这里插入图片描述

ApplicationEventMulticaster接口只有一个直接实现抽象类AbstractApplicationEventMulticaster及SimpleApplicationEventMulticaster实现类;

ApplicationEventMulticaster接口源码如下:

public interface ApplicationEventMulticaster {
    

	/**
	 * 添加监听器以接收所有的事件通知
	 */
	void addApplicationListener(ApplicationListener<?> listener);

	/**
	 * 添加监听器以接收所有的事件通知,参数是监听器bean名称
	 */
	void addApplicationListenerBean(String listenerBeanName);

	/**
	 * 从通知列表中删除监听器
	 * @param listener 将被删除的监听器
	 */
	void removeApplicationListener(ApplicationListener<?> listener);

	/**
	 * 从通知列表中删除监听器
	 * @param listenerBeanName 将被删除的监听器
	 */
	void removeApplicationListenerBean(String listenerBeanName);

	/**
	 * 删除注册到代理上的所有监听器
	 * 在remove调用之后,代理不会对事件通知执行任何操作直到有新的监听器注册
	 */
	void removeAllListeners();

	/**
	 * 将给定的事件广播到对应的监听器上
	 * @param 需要广播的事件
	 */
	void multicastEvent(ApplicationEvent event);

	/**
	 * 将应用程序事件广播到对应的监听器上
	 * @param 需要广播的事件
	 * @param 事件类型
	 */
	void multicastEvent(ApplicationEvent event, @Nullable ResolvableType eventType);

}

AbstractApplicationEventMulticaster类是ApplicationEventMulticaster接口的抽象实现,提供基本的监听器注册工具方法(注册和移除监听器);默认情况下不允许同一个监听器有多个实例,因为该类会将监听器保存在ListenerRetriever集合类的Set集合中。

AbstractApplicationEventMulticaster类属性源码如下:

public abstract class AbstractApplicationEventMulticaster
      implements ApplicationEventMulticaster, BeanClassLoaderAware, BeanFactoryAware {
    
	//创建监听器助手类,用于存放应用程序的监听器集合,参数是否是预过滤监听器为false
   private final ListenerRetriever defaultRetriever = new ListenerRetriever(false);
	//ListenerCacheKey是基于事件类型和源类型的类作为key用来存储监听器助手ListenerRetriever
   final Map<ListenerCacheKey, ListenerRetriever> retrieverCache = new ConcurrentHashMap<>(64);
	//类加载器
   @Nullable
   private ClassLoader beanClassLoader;
	//IOC容器工厂类
   @Nullable
   private ConfigurableBeanFactory beanFactory;
  //互斥的监听器助手类
   private Object retrievalMutex = this.defaultRetriever;
}

ListenerRetriever监听器助手类(封装一组特定目标监听器的帮助类,允许有效地检索预过滤的监听器,此助手的实例按照时间类型和源类型缓存):

	private class ListenerRetriever {
    
		//存放应用程序事件监听器,有序、不可重复
		public final Set<ApplicationListener<?>> applicationListeners = new LinkedHashSet<>();
		//存放应用程序事件监听器bean名称,有序,不可重复
		public final Set<String> applicationListenerBeans = new LinkedHashSet<>();
		//是否预过滤监听器
		private final boolean preFiltered;

		public ListenerRetriever(boolean preFiltered) {
    
			this.preFiltered = preFiltered;
		}
		//获取应用程序的时间监听器
		public Collection<ApplicationListener<?>> getApplicationListeners() {
    
      //创建一个指定大小的ApplicationListener监听器List集合
			List<ApplicationListener<?>> allListeners = new ArrayList<>(
					this.applicationListeners.size() + this.applicationListenerBeans.size());
			allListeners.addAll(this.applicationListeners);
      //如果存放监听器bean name的集合不为空
			if (!this.applicationListenerBeans.isEmpty()) {
    
        //获取IOC容器工厂类
				BeanFactory beanFactory = getBeanFactory();
				for (String listenerBeanName : this.applicationListenerBeans) {
    
					try {
    
            //获取指定bean name的监听器实例
						ApplicationListener<?> listener = beanFactory.getBean(listenerBeanName, ApplicationListener.class);
            //判定如果是预过滤的监听器或者集合中不包含监听器实例则添加到集合中
						if (this.preFiltered || !allListeners.contains(listener)) {
    
							allListeners.add(listener);
						}
					}
					catch (NoSuchBeanDefinitionException ex) {
    
						// Singleton listener instance (without backing bean definition) disappeared -
						// probably in the middle of the destruction phase
					}
				}
			}
			if (!this.preFiltered || !this.applicationListenerBeans.isEmpty()) {
    
				AnnotationAwareOrderComparator.sort(allListeners);
			}
			return allListeners;
		}
	}

AbstractApplicationEventMulticaster#addApplicationListener方法添加应用程序监听器类:

	@Override
	public void addApplicationListener(ApplicationListener<?> listener) {
    
    //锁定监听器助手对象
		synchronized (this.retrievalMutex) {
    
			// 如果已经注册,则显式删除已经注册的监听器对象
			// 为了避免调用重复的监听器对象
			Object singletonTarget = AopProxyUtils.getSingletonTarget(listener);
			if (singletonTarget instanceof ApplicationListener) {
    
        //删除监听器对象
				this.defaultRetriever.applicationListeners.remove(singletonTarget);
			}
      //新增监听器对象
			this.defaultRetriever.applicationListeners.add(listener);
      //清空监听器助手缓存Map
			this.retrieverCache.clear();
		}
	}

	@Override
	public void addApplicationListenerBean(String listenerBeanName) {
    
    //锁定监听器助手对象
		synchronized (this.retrievalMutex) {
    
      //新增bean name为listenerBeanName的监听器对象到集合之中
			this.defaultRetriever.applicationListenerBeans.add(listenerBeanName);
      //清空监听器助手缓存Map
			this.retrieverCache.clear();
		}
	}

删除监听器对象:

	@Override
	public void removeApplicationListener(ApplicationListener<?> listener) {
    
		synchronized (this.retrievalMutex) {
    
			this.defaultRetriever.applicationListeners.remove(listener);
			this.retrieverCache.clear();
		}
	}

	@Override
	public void removeApplicationListenerBean(String listenerBeanName) {
    
		synchronized (this.retrievalMutex) {
    
			this.defaultRetriever.applicationListenerBeans.remove(listenerBeanName);
			this.retrieverCache.clear();
		}
	}

	@Override
	public void removeAllListeners() {
    
		synchronized (this.retrievalMutex) {
    
			this.defaultRetriever.applicationListeners.clear();
			this.defaultRetriever.applicationListenerBeans.clear();
			this.retrieverCache.clear();
		}
	}

AbstractApplicationEventMulticaster#getApplicationListeners方法获取监听器对象(匹配指定的时间类型,不匹配很早就被排除在外的监听器)

	protected Collection<ApplicationListener<?>> getApplicationListeners(
			ApplicationEvent event, ResolvableType eventType) {
    
		//事件源,事件最初发生在其上的对象
		Object source = event.getSource();
    //事件源class对象
		Class<?> sourceType = (source != null ? source.getClass() : null);
    //创建基于事件源,和源类型的监听器助手cacheKey
		ListenerCacheKey cacheKey = new ListenerCacheKey(eventType, sourceType);

		//快速检测监听器助手缓存ConcurrentHashMap中是否存在指定的cacheKey
		ListenerRetriever retriever = this.retrieverCache.get(cacheKey);
		if (retriever != null) {
    
      //如果存在指定的key,则返回应用程序的监听器对象
			return retriever.getApplicationListeners();
		}
		//如果类加载器为null,或者事件源在给定的类加载器上下文是安全的并且源类型为null或者源类型在指定上下文是安全的
		if (this.beanClassLoader == null ||
				(ClassUtils.isCacheSafe(event.getClass(), this.beanClassLoader) &&
						(sourceType == null || ClassUtils.isCacheSafe(sourceType, this.beanClassLoader)))) {
    
			// 同步从ListenerRetriever监听器助手中获取指定的监听器
			synchronized (this.retrievalMutex) {
    
				retriever = this.retrieverCache.get(cacheKey);
				if (retriever != null) {
    
          //返回监听器助手中存储的监听器对象
					return retriever.getApplicationListeners();
				}
				retriever = new ListenerRetriever(true);
        //实际检索给定事件和源类型的应用程序监听器
				Collection<ApplicationListener<?>> listeners =
						retrieveApplicationListeners(eventType, sourceType, retriever);
				this.retrieverCache.put(cacheKey, retriever);
				return listeners;
			}
		}
		else {
    
			// 无ListenerRetriever监听器助手 -> 无需同步缓存
			return retrieveApplicationListeners(eventType, sourceType, null);
		}
	}

GitHub地址:https://github.com/mingyang66/spring-parent

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/yaomingyang/article/details/109057426

智能推荐

Linux 下的一个全新的性能测量和调式诊断工具 Systemtap, 第 2 部分: DTrace_ctthuangcheng的博客-程序员宝宝

DTrace的原理本系列文章详细地介绍了一个 Linux 下的全新的调式、诊断和性能测量工具 Systemtap 和它所依赖的基础 kprobe 以及促使开发该工具的先驱 DTrace 并给出实际使用例子使读者更进一步了解和认识这些工具。 本文是该系列文章之二,它详细地讲解了 DTrace 的原理。本系列文章之一讲解了 kprobe 的原理、编程接口、局限性和使用注意事项并给出实际使用示例帮助读者

get请求与post请求的特点_........千年老妖的博客-程序员宝宝_get请求特点

GET请求具有以下的几个特点:GET请求可被缓存GET请求保留在浏览器历史记录中GET请求可被收藏为书签GET请求不应在处理敏感数据时使用GET请求有长度限制GET请求只应当用于取回数据POST请求的特点如下:POST请求不会被缓存POST请求不会保留在浏览器历史记录中POST请求不能被收藏为书签POST请求对数据长度没有要求...

Qt5下实现摄像头预览及捕获图像方法二(openCV3与Qt5交互使用)_worthsen的博客-程序员宝宝

致谢:http://www.cnblogs.com/annt/p/ant003.html前言:OpenCV对图像及视频的处理方便且很专业,对于摄像头的支持也很好,但有个不足就是它虽然具有GUI模块(即highgui),但是实在是很简陋,就连一个按键都无法直接实现(需要借助滚动条实现),这一点难以满足可视化的图像处理的想法;另一方面,Qt作为一个优秀的图形库,在GUI上表现出色,且界面设计可

【DX11习题学习二】第六章练习 Drawing in Direct3D(上)_键盘崩坏的博客-程序员宝宝

本系列只针对书中每章节的编程练习题,不涉及书中的数学题,需要数学部分的解答请点击对应原书 P137 4.7EXERCISES1. Write down the D3D10_INPUT_ELEMENT_DESC array for the following vertex structure:struct Vertex{XMFLOAT3 Pos;XMFLO

10个运维人员需要知道的”系统进程”_study-linux的博客-程序员宝宝

在日常的运维工作中,当我们习惯性的执行ps命令后会看到很多“奇奇怪怪”的进程,而这些进程大部门都是系统的内核进程。很多同学对之了解的甚少,因此今天就为大家整理一篇入门级的系统进程介绍帖,希望能够帮助大家对操作系统进程的理解。在日常的运维工作中,当我们习惯性的执行ps命令后会看到很多“奇奇怪怪”的进程,而这些进程大部门都是系统的内核进程。很多同学对之了解的甚少,因此今天就为大家整

随便推点

day3-python-集合文件操作函数_weixin_30446197的博客-程序员宝宝

一、集合主要作用:去重关系测试, 交集\差集\并集\反向(对称)差集#!/usr/bin/env python# -*- coding:utf-8 -*-list_1 = [1,4,5,7,3,6,7,9]list_1 = set(list_1)list_2 = set([2,6,0,66,22,8,4])print(list_1,list_2)...

Windows密码复杂性要求_allway2的博客-程序员宝宝_密码必须符合复杂性要求

密码必须符合复杂性要求介绍 "密码必须满足复杂性要求" 安全策略设置的最佳做法、位置、值和安全注意事项。参考"密码必须满足复杂性要求" 策略设置确定密码是否必须满足一系列对强密码重要的指南。 启用此策略设置需要密码才能满足以下要求:在更改或创建密码时, 将强制执行复杂性要求。Windows Server 密码复杂性要求中包含的规则属于 Passfilt, 不能直接修改。启用...

NOIP2002-普及组复赛-第二题-级数求和_weixin_30345577的博客-程序员宝宝

题目描述Description  已知:Sn= 1+1/2+1/3+…+1/n。显然对于任意一个整数K,当n足够大的时候,Sn大于K。  现给出一个整数K(1&lt;=k&lt;=15),要求计算出一个最小的n;使得Sn>K。输入输出格式Input/output输入格式:一个正整数K。输出格式:一个正整数N。...

python练习12_い木乄子゛的博客-程序员宝宝

题目:判断101-200之间有多少个素数,并输出所有素数。 #!/usr/bin/python# -*- coding: UTF-8 -*-#from math import sqrtprime = []flag = Truefor i in range(101, 201): k = int(sqrt(i)) for j in range(2, k + 1): ...

python—异常处理_didaojiao4342的博客-程序员宝宝

Python 之-异常处理异常和错误part1:程序中难免出现错误,而错误分成两种1语法错误(这种错误,根本过不了Python解释器的语法检测,必须在程序执行前就改正)#语法错误示范一、if#语法错误示范二、def test: pass#语法错误示范三、print(haha2逻辑错误(逻辑错误)#用户输入...

spring boot 自动配置_中国lanwp的博客-程序员宝宝

文章目录springboot自动化配置spring boot mybatis plus依赖spring boot自动配置相关文件启动的自动配置类MybatisPlusAutoConfigurationspringboot自动化配置这里拿mybatis-plus-boot-starter 为例子说明,其他类似spring boot mybatis plus依赖spring boot引入依赖 - 包含了mybatis和mybatis-spring 及 mybatis-plus3.3.2版本

推荐文章

热门文章

相关标签