Spring事件监听源码解析

Spring事件监听机制源码解析 主要内容1 什么是事件监听机制2 JDK的事件监听机制2.1 EventObject(事件)2.2 EventListener(事件监听器)2.3 EventPublisher(事件发布器)2.4 基于jdk的事件机制示例2.4.1 事件源(红绿灯)2.4.1 事件2.4.2 事件监听器2.4.3 事件发布器2.4.4 测试代码3 Spring的事件监听机制3.1 Spring事件(ApplicationEvent)3.2 Spring事件监听器(ApplicationListener)3.3 Spring 阅读详情

spring事件监听机制离不开容器IOC特性提供的支持,比如容器会自动创建事件发布器,自动识别用户注册的监听器并进行管理,在特定的事件发布后会找到对应的事件监听器并对其监听方法进行回调。Spring帮助用户屏蔽了关于事件监听机制背后的很多细节,使用户可以专注于业务层面进行自定义事件开发。然而我们对内部的实现还是有一些疑问,比如:

• 事件发布器ApplicationEventMulticaster是何时被初始化的,初始化过程中都做了什么?
• 注册事件监听器的过程是怎样的,容器怎么识别出它们并进行管理?
• 容器发布事件的流程是怎样的?它如何根据发布的事件找到对应的事件监听器,事件和由该事件触发的监听器之间的匹配规则是怎样的?

初始化事件发布器流程

真正的事件发布器是ApplicationEventMulticaster,它定义在AbstractApplicationContext中,并在ApplicationContext容器启动的时候进行初始化。在容器启动的refrsh()方法中可以找到初始化事件发布器的入口方法,如下图所示:
在这里插入图片描述

/**
	 * Initialize the ApplicationEventMulticaster.
	 * Uses SimpleApplicationEventMulticaster if none defined in the context.
	 * @see org.springframework.context.event.SimpleApplicationEventMulticaster
	 */
	protected void initApplicationEventMulticaster() {
		ConfigurableListableBeanFactory beanFactory = getBeanFactory();
		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 {
			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() + "]");
			}
		}
	}


这里会根据核心容器beanFactory中是否有id为applicationEventMulticaster的bean分两种情况:

(1)容器中已有id为applicationEventMulticaster的bean:直接从容器缓存获取或是创建该bean实例,并交由成员变量applicationEventMulticaster保存。当用户自定义了事件发布器并向容器注册时会执行该流程。
(2)容器中不存在applicationEventMulticaster的bean:这是容器默认的执行流程,会创建一个SimpleApplicationEventMulticaster,其仅在实现事件发布器基本功能(管理事件监听器以及发布容器事件)的前提下,增加了可以设置任务执行器Executor和错误处理器ErrorHandler的功能,当设置Executor为线程池时,则会以异步的方式对事件监听器进行回调,而ErrorHandler允许我们在回调方法执行错误时进行自定义处理。默认情况下,这两个变量都为null。

在这里插入图片描述
之后会调用beanFactory.registerSingleton方法将创建的SimpleApplicationEventMulticaster实例注册为容器的单实例bean。
初始化事件发布器总结一句话:由容器实例化用户自定义的事件发布器或者由容器帮我们创建一个简单的事件发布器并交由容器管理。

注册事件监听器流程

注册事件监听器的流程在初始化事件发布器之后,如下图所示:

在这里插入图片描述

/**
	 * Add beans that implement ApplicationListener as listeners.
	 * Doesn't affect other listeners, which can be added without being beans.
	 */
	protected void registerListeners() {
		// 首先注册静态指定的监听器。
		for (ApplicationListener<?> listener : getApplicationListeners()) {
			getApplicationEventMulticaster().addApplicationListener(listener);
		}

		// 不要在这里初始化FactoryBeans:我们需要保留所有常规Bean
		// 未初始化以允许后处理器应用于它们!
		String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
		for (String listenerBeanName : listenerBeanNames) {
			getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
		}

		// 发布早期应用程序事件
		Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
		this.earlyApplicationEvents = null;
		if (earlyEventsToProcess != null) {
			for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
				getApplicationEventMulticaster().multicastEvent(earlyEvent);
			}
		}
	}

容器事件发布流程

org.springframework.context.support.AbstractApplicationContext#publishEvent(java.lang.Object, ResolvableType)

将给定事件发布给所有侦听器
在这里插入图片描述
前面说,在启动的时候如果没有一个beanName叫做applicationEventMulticaster的ApplicationEventMulticaster,那使用的就是SimpleApplicationEventMulticaster,该组件会在容器启动时被自动创建,并以单例的形式存在,管理了所有的事件监听器,并提供针对所有容器内事件的发布功能。

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

@Override 
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) { 
	//获取事件类型 
	ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event)); 
	//获取事件发布器内的任务执行器,默认该方法返回null 
	Executor executor = getTaskExecutor(); 
	//遍历所有和事件匹配的事件监听器 
	for (ApplicationListener<?> listener : getApplicationListeners(event, type)) { 
		if (executor != null) { 
			//异步回调监听方法 
			executor.execute(() -> invokeListener(listener, event)); 
		} else { 
			//同步回调监听方法 
			invokeListener(listener, event); 
		} 
	} 
}

如何根据事件类型找到匹配的所有事件监听器?

org.springframework.context.event.AbstractApplicationEventMulticaster#getApplicationListeners(ApplicationEvent, ResolvableType)

/**
	 * Return a Collection of ApplicationListeners matching the given
	 * event type. Non-matching listeners get excluded early.
	 * @param event the event to be propagated. Allows for excluding
	 * non-matching listeners early, based on cached matching information.
	 * @param eventType the event type
	 * @return a Collection of ApplicationListeners
	 * @see org.springframework.context.ApplicationListener
	 */
	protected Collection<ApplicationListener<?>> getApplicationListeners(
			ApplicationEvent event, ResolvableType eventType) {
                      // 获取事件中的事件源对象
		Object source = event.getSource();
		// 获取事件源类型
		Class<?> sourceType = (source != null ? source.getClass() : null);
		// 以事件类型和事件源类型为参数构建一个cacheKey ,用于从缓存map中获取与之匹配的监听器列表
		ListenerCacheKey cacheKey = new ListenerCacheKey(eventType, sourceType);

		// 根据cacheKey从缓存中获取CachedListenerRetriever
		ListenerRetriever retriever = this.retrieverCache.get(cacheKey);
		if (retriever != null) {
			return retriever.getApplicationListeners();
		}

		if (this.beanClassLoader == null ||
				(ClassUtils.isCacheSafe(event.getClass(), this.beanClassLoader) &&
						(sourceType == null || ClassUtils.isCacheSafe(sourceType, this.beanClassLoader)))) {
			// Fully synchronized building and caching of a 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 {
			// No ListenerRetriever caching -> no synchronization necessary
			return retrieveApplicationListeners(eventType, sourceType, null);
		}
	}

如果事件时第一次发布,会遍历所有的事件监听器,并根据事件类型和事件源类型进行匹配:

org.springframework.context.event.AbstractApplicationEventMulticaster#retrieveApplicationListeners

/**
	 * Actually retrieve the application listeners for the given event and source type.
	 * @param eventType the event type
	 * @param sourceType the event source type
	 * @param retriever the ListenerRetriever, if supposed to populate one (for caching purposes)
	 * @return the pre-filtered list of application listeners for the given event and source type
	 */
	private Collection<ApplicationListener<?>> retrieveApplicationListeners(
			ResolvableType eventType, @Nullable Class<?> sourceType, @Nullable ListenerRetriever retriever) {
                       // 存放监听器的列表
		List<ApplicationListener<?>> allListeners = new ArrayList<>();
		Set<ApplicationListener<?>> listeners;
		Set<String> listenerBeans;
		synchronized (this.retrievalMutex) {
			listeners = new LinkedHashSet<>(this.defaultRetriever.applicationListeners);
			listenerBeans = new LinkedHashSet<>(this.defaultRetriever.applicationListenerBeans);
		}

		// 添加以编程方式注册的侦听器,
		// 包括来自ApplicationListenerDetector的侦听器(单例bean和内部bean)。
		for (ApplicationListener<?> listener : listeners) {
			if (supportsEvent(listener, eventType, sourceType)) {
				if (retriever != null) {
					retriever.applicationListeners.add(listener);
				}
				allListeners.add(listener);
			}
		}

		// 按bean名称添加侦听器,这可能与上面通过编程注册的侦听器重叠,
		// 但这里可能有额外的元数据。
		if (!listenerBeans.isEmpty()) {
			ConfigurableBeanFactory beanFactory = getBeanFactory();
			for (String listenerBeanName : listenerBeans) {
				try {
					if (supportsEvent(beanFactory, listenerBeanName, eventType)) {
						ApplicationListener<?> listener =
								beanFactory.getBean(listenerBeanName, ApplicationListener.class);
						if (!allListeners.contains(listener) && supportsEvent(listener, eventType, sourceType)) {
							if (retriever != null) {
								if (beanFactory.isSingleton(listenerBeanName)) {
									retriever.applicationListeners.add(listener);
								}
								else {
									retriever.applicationListenerBeans.add(listenerBeanName);
								}
							}
							allListeners.add(listener);
						}
					}
					else {
						// 删除最初来自ApplicationListenerDetector的不匹配侦听器,
						// 可能会被上面额外的BeanDefinition元数据(例如工厂方法泛型)排除。
						Object listener = beanFactory.getSingleton(listenerBeanName);
						if (retriever != null) {
							retriever.applicationListeners.remove(listener);
						}
						allListeners.remove(listener);
					}
				}
				catch (NoSuchBeanDefinitionException ex) {
					// 单一侦听器实例(没有支持bean定义)消失-可能在销毁阶段中期}
			}
		}
		//对匹配的监听器列表进行排序
		AnnotationAwareOrderComparator.sort(allListeners);
		if (retriever != null && retriever.applicationListenerBeans.isEmpty()) {
			retriever.applicationListeners.clear();
			retriever.applicationListeners.addAll(allListeners);
		}
		return allListeners;
	}

容器事件发布的整个流程,可以总结如下:
在这里插入图片描述

手动安装SeuratData包中pbmc3k数据集的详细步骤与避坑指南 本文提供了手动安装SeuratData包中pbmc3k数据集的详细步骤与避坑指南。针对国内用户网络不稳定导致自动下载失败的问题,文章核心介绍了如何从错误信息中获取下载链接,使用浏览器或下载工具完成手动下载,并通过指定本地文件路径和参数在R中成功安装。该方法同样适用于SeuratData包中的其他数据集,是单细胞分析入门的必备生存技能。 阅读详情

相关推荐

python 爬虫 xpath 存储到数据库

参考

我是张先生 1288

人人都能看懂的Spring源码解析,spring的事件监听机制

ContextClosedEvent 上下文关闭事件ContextRefreshedEvent 上下文刷新完成事件ContextStartedEvent 上下文启动事件ContextStoppedEvent 上下文停止事件它们都继承,而ApplicationContextEvent又继承了ApplicationEvent。与Spring上下文状态变化相关的事件都继承ApplicationContextEvent,而ApplicationEvent类型的事件则范围更广。其中。

weixin_43889578的博客 425

MT6771 Android13 背光曲线调试与光感数据校准实战

本文详细介绍了MT6771平台在Android 13系统上进行背光曲线调试与光感数据校准的实战经验。针对高亮度环境下背光误调节问题,深入分析了光感数据上报机制,并提供了驱动层配置修改、背光曲线优化及常见问题解决方案,帮助开发者快速定位并解决类似问题。

moon9的博客 287

Spring - 事件监听机制 源码解析

事件事件生产者事件消费者控制器 (管理生产者、消费者和事件之间的注册监听关系)在Spring中,事件监听机制主要实现是通过事件、事件监听器、事件发布者和事件广播器来实现。

小工匠 3万+

基于YOLO26深度学习框架的人脸识别门禁系统的算法研究实现方法

本文研究了基于YOLO26深度学习框架的人脸识别门禁系统实现方法。系统采用YOLO26目标检测算法,通过CSPDarknet53主干网络、特征金字塔结构和注意力机制实现高效人脸检测。研究内容包括数据预处理、模型训练优化和身份验证等关键技术,使用迁移学习策略和CIoU损失函数提升检测精度。该系统可应用于智能安防场景,具有实时性强、识别准确的特点,为门禁管理提供了智能化解决方案。

一键难忘的博客 766

Idea插件Plugins无法联网下载 解决方法(终极版必解决!)

插件联网的Bug疑难杂症,网络上不一样的解决方式以及独特的彩蛋!包解决

码农研究僧的博客 5513

spring源码解析之ApplicationListener(事件监听)

一 :Spring是如何发布事件的? 1.1)自己写一个TestApplicationListener实现ApplicationListener​接口,并且把该组件加入到容器中. 源码: @Component public class TestApplicationListener implements ApplicationListener { @Override public...

代码天蝎 609

SPI协议详解(图文并茂+超详细)

先说串口 因为之前写过一篇UART,通用串行异步通讯协议,UART的相关资料 因为UART没有时钟信号,无法控制何时发送数据,也无法保证双发按照完全相同的速度接收数据。因此,双方以不同的速度进行数据接收和发送,就会出现问题。 如果要解决这个问题,UART为每个字节添加额外的起始位和停止位,以帮助接收器在数据到达时进行同步; 双方还必须事先就传输速度达成共识(设置相同的波特率,例如每秒9600位)。 传输速率如果有微小差异不是问题,因为接收器会在每个字节的开头重新同步。相应的协议如下图所示; 如果您注意到

一名热爱技术的工程师的博客。分享技术干货,记录美好生活。永远相信美好的事情即将发生。 33万+

Spring事件监听机制深度解析:registerListeners源码揭秘

深入剖析了Spring容器启动中的关键步骤registerListeners(),揭示了Spring事件驱动模型的核心机制。

张小洛的BOLG 960

软件需求规格说明书(SRS)深入解析

摘要: SRS(软件需求规格说明书)是定义系统功能、性能与接口的核心文档,为开发、测试、项目管理提供依据。标准结构包括引言、总体描述、功能/非功能需求、接口等模块。撰写需确保清晰、可验证、无歧义,避免模糊术语。示例展示学生注册模块的需求写法,强调性能与安全性要求。推荐使用Confluence、StarUML等工具辅助编写,交付时需包含主文档、原型图及需求跟踪矩阵。SRS应兼具技术性与管理性,作为沟通桥梁和验收标准。

moton2017的博客 2915

LVGL(lv_table)

LVGL中的lv_table是一个轻量级表格控件,用于显示行列式文本数据。它支持设置单元格内容/样式、行列调整、事件响应等基础功能,适用于参数配置、数据展示等场景。通过API可快速创建表格,设置行列数、填充数据,并自定义对齐方式与样式。但需注意默认无滚动条、行数限制等问题。该控件适合简单表格需求,复杂交互需结合自定义事件处理。

m0_49476241的博客 1262

Spring事件监听器源码深度解析

📌 Spring事件监听器源码解析摘要 Spring事件机制采用观察者模式,核心架构包含四大层级: 事件发布层:通过ApplicationEventPublisher接口发布事件 广播处理层:SimpleApplicationEventMulticaster负责事件分发 监听管理层:ApplicationListener接口体系处理事件订阅 注解支持层:@EventListener注解的解析实现 关键实现细节: 事件发布入口在AbstractApplicationContext.publishEvent(

futurn_hero的博客 289

WblockCloneObjects克隆一个图纸内的实体包括块参照,同名块参照的处理

public static void HeBingTu2(double lieJu, List<string> filePaths) { Document doc = Application.DocumentManager.MdiActiveDocument; Database db = doc.Database; using (DocumentLock docLock = doc.Lock...

1108

观察者模式,事件监听机制底层实现,Spring 事件监听源码解析

观察者模式,事件监听机制底层实现,Spring 事件监听源码解析

Harvey's Blog 1019

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

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

文章目录Pre应用原理配置类 Pre Spring5源码 - 11 Spring事件监听机制_源码篇 应用 原理 Spring提供的事件机制,默认是同步的。如果想要使用异步事件监听,可以自己实现ApplicationEventMulticaster接口,并在Spring容器中注册id为applicationEventMulticaster的Bean , 设置 executor 配置类 package com.artisan.eventlistener2; import org.springfram

小工匠 2万+

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

Spring事件监听机制@EventListener源码解析

目录 1、前期准备 2、创建和注册事件监听器 (1)EventListenerMethodProcessor.class (2)SmartInitializingSingleton -> Spring的回调 3、发布事件 1、前期准备 Spring容器在启动的时候初始化EventListenerMethodProcessor和 DefaultEventListenerFactory,当Spring Bean 创建完成后,会调用EventListenerMethodProcessor的

swadian2008的博客 1160

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

Spring5源码 - 13 Spring事件监听机制_@EventListener源码解析

文章目录Pre概览@EventListener Pre Spring5源码 - 10 Spring事件监听机制_应用篇 Spring5源码 - 11 Spring事件监听机制_源码篇 Spring5源码 - 12 Spring事件监听机制_异步事件监听应用及源码解析 通过上面三篇文章的学习,是不是发现没有看到Spring是如何解析@EventListener注解的呢? Let’s go ~~~ 概览 @EventListener ...

小工匠 2万+

Spring 源码解析之IOC 的多播器和事件监听机制

一 接上面的接受,继续介绍refresh 方法。 1. 主方法。 public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) { this(); register(annotatedClasses); refresh(); } 2. 进入refresh方法,一共12步方法。 ...

pengweismile的专栏 1172

Spring 事件监听器示例及源码解析

Spring 事件监听器示例及源码解析 源码解析 ApplicationEvent public abstract class ApplicationEvent extends EventObject { //序列化 private static final long serialVersionUID = 7099057708183571937L; //时间戳 private final long timestamp = System.currentTimeMillis(

空巷。的博客 359

spring — spring中事件监听机制源码解析(五)

关于spring相关文章回顾: 一、spring中Bean的初始化过程 二、spring中bean的生命周期 三、spring中AOP技术解析 四、spring中的事件驱动机制解析 一、Spring中事件驱动三大对象 spring事件ApplicationEvent继承自EventObject,Spring提供了ApplicationEventPublisher接口作为事件发布者(ApplicationContext接口继承了该接口,担当着事件发布者的角色)。 Spring提供了ApplicationEv

qq_38658567的博客 477

Spring 源码解析 ---- 事件监听

一. 测试用例 package main.java.com.wenniuwuren.spring.event.listener; import org.springframework.context.ApplicationEvent; /** * 定义监听事件 * Created by hzzhuyibin on 2016/11/22. */ public class TestEve

wenniuwuren 1527

spring事件监听器系列二:@EventListener注解原理

前面的笔记中,有写过,我们要在spring中声明一个事件监听器,有两种方式,一种是实现ApplicationListener接口,一种是通过@EventListener注解来修饰一个方法,并在该注解中,指定要监听的事件,那这个方法在事件发生的时候,会被回调 这两种机制,其实我们先不看代码,去考虑下,实现的方式很有可能就是: 对于实现接口这种方式,是ApplicationListenerDetector这个类来完成解析的 对于注解这种方式,是EventListenerMethodProcessor和Defau

小小少年的博客 4661

Spring事件监听流程分析【源码浅析】

一、简介 Spring早期是通过实现ApplicationListener接口来定义监听事件,在spring4.2的时候开始我们可以通过@EventListener注解来定义监听事件,ApplicationListener接口定义如下: @FunctionalInterface public interface ApplicationListener<E extends Applicat...

Mr_Liu946的博客 825

Spring Boot 启动流程源码解析

本文解析了Spring Boot的启动流程,主要分为四个阶段: 启动前准备:初始化SpringApplication,加载初始器和监听器,打印Banner 创建应用上下文:实例化ApplicationContext并准备环境 刷新上下文:加载Bean定义,实例化单例Bean 启动完成:发布就绪事件 关键点包括: 通过run()方法启动,完成应用类型推断 从spring.factories加载初始器和监听器 使用StopWatch监控启动时间 事件驱动机制贯穿整个启动过程 启动流程通过分层设计实现了高度可扩展

qq_43414012的博客 1704

Spring中事件监听器

事件监听器ApplicationListener是观察者模式的一个应用,当被观察的事件发生改变时需要通知该事件的订阅者针对这个事件做出对应行为。它将事件的发布和订阅进行解耦,因此可以独立修改事件发布或者订阅方便代码扩展和维护。

qq_31124713的博客 816

深度解析 Spring 事件监听机制

Spring的事件监听机制基于观察者模式,实现了组件间的松耦合通信。核心包括事件(ApplicationEvent)、监听器(ApplicationListener)和发布器(ApplicationEventPublisher)。事件发布流程分为包装事件、获取监听器和广播事件三步。监听器可通过传统接口实现或@EventListener注解方式注册。高级特性支持异步处理(@Async)、事务同步事件等。源码分析表明,事件多播器(ApplicationEventMulticaster)是广播核心,默认实现Sim

csdn_tom_168的博客 1236
上一篇: Spring事件监听机制
下一篇: UML基础模型
CodAlun
博客等级 码龄8年 46粉丝 96原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值