Spring事件监听源码解析

这篇具有很好参考价值的文章主要介绍了Spring事件监听源码解析。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

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

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

初始化事件发布器流程

真正的事件发布器是ApplicationEventMulticaster,它定义在AbstractApplicationContext中,并在ApplicationContext容器启动的时候进行初始化。在容器启动的refrsh()方法中可以找到初始化事件发布器的入口方法,如下图所示:
Spring事件监听源码解析,框架,Java,spring,rpc,java

/**
	 * 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。

Spring事件监听源码解析,框架,Java,spring,rpc,java
之后会调用beanFactory.registerSingleton方法将创建的SimpleApplicationEventMulticaster实例注册为容器的单实例bean。
初始化事件发布器总结一句话:由容器实例化用户自定义的事件发布器或者由容器帮我们创建一个简单的事件发布器并交由容器管理。

注册事件监听器流程

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

Spring事件监听源码解析,框架,Java,spring,rpc,java

/**
	 * 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)

将给定事件发布给所有侦听器
Spring事件监听源码解析,框架,Java,spring,rpc,java
前面说,在启动的时候如果没有一个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;
	}

容器事件发布的整个流程,可以总结如下
Spring事件监听源码解析,框架,Java,spring,rpc,java文章来源地址https://www.toymoban.com/news/detail-659464.html

到了这里,关于Spring事件监听源码解析的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【框架源码】Spring源码解析之Bean生命周期流程

    观看本文前,我们先思考一个问题,什么是Spring的bean的生命周期?这也是我们在面试的时候,面试官常问的一个问题。 在没有Spring之前,我们创建对象的时候,采用new的方式,当对象不在被使用的时候,由Java的垃圾回收机制回收。 而 Spring 中的对象是 bean,bean 和普通的 J

    2024年02月09日
    浏览(45)
  • 【Spring | 事件监听详解】

    上篇 Spring 事件监听概述 对 Spring 事件监听的机制有了个基本的了解。 本篇来详细的解读下Spring 的 事件监听机制 。    ApplicationEvent 最重要的子类是 ApplicationContextEvent 抽象类, ApplicationContextEvent 是spring容器Context生命周期事件的基类。 ApplicationContextEvent 的有四个子类,如

    2024年02月12日
    浏览(36)
  • Spring高手之路15——掌握Spring事件监听器的内部逻辑与实现

    在阅读本文之前需要你已经对事件监听器有了简单的了解,或去阅读前面的文章《 Spring高手之路7——事件机制与监听器的全面探索 》   在 Spring 中, ApplicationContext 可以形成一个层次结构,通常由主容器和多个子容器组成。一个常见的疑问是:当一个事件在其中一个容器

    2024年02月06日
    浏览(48)
  • Spring boot 实现监听 Redis key 失效事件

    方式一:修改配置文件 redis.conf 方式二:命令行开启 notify-keyspace-events 选项的默认值为空 notify-keyspace-events 的参数可以是以下字符的 任意组合 , 它指定了服务器该发送哪些类型的通知。 字符 发送的通知 K 键空间通知,所有通知以 keyspace@ 为前缀 E 键事件通知,所有通知以

    2024年02月20日
    浏览(40)
  • 【SpringBoot笔记34】Spring Events事件驱动编程之事件的发布和监听操作

    这篇文章,主要介绍Spring Events事件驱动编程之事件的发布和监听操作。 目录 一、基于接口实现 1.1、自定义事件 1.2、主动发布事件 1.3、监听事件对象

    2024年02月16日
    浏览(46)
  • Spring高手之路7——事件机制与监听器的全面探索

      观察者模式是一种行为设计模式,它定义了对象之间的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知并被自动更新。在这个模式中,改变状态的对象被称为主题,依赖的对象被称为观察者。 举个实际的例子: 事件源(Event Source) :可以视

    2024年02月11日
    浏览(44)
  • 微服务 Spring Cloud 8,开源RPC框架如何选型?

    大家好,我是哪吒。 1、跟语言平台绑定的开源RPC框架 Dubbo :国内最早开源的RPC框架,由阿里巴巴公司开发并于2011年末对外开源,仅支持Java语言。 Motan :微博内部使用的RPC框架,于2016年对外开源,仅支持Java语言。 Tars :腾讯内部使用的RPC框架,于2017年对外开源,仅支持

    2024年02月05日
    浏览(43)
  • Java键盘事件处理及监听机制解析

    Java事件处理采用了委派事件模型。在这个模型中,当事件发生时,产生事件的对象将事件信息传递给事件的监听者进行处理。在Java中,事件源是产生事件的对象,比如窗口、按钮等;事件是承载事件源状态改变时的对象,比如键盘事件、鼠标事件、窗口事件等等。当事件发

    2024年02月13日
    浏览(38)
  • Activiti7流程结束监听事件中,抛出的异常无法被spring全局异常捕捉

    activiti7中,提供了 ProcessRuntimeEventListener 监听器,用于监听流程实例的结束事件 上述代码中,由于1/0会抛出运行时异常,理论上来说应该被我们的全局异常所捕获 实际情况是无法捕获 既然异常没有被一层一层的抛出去直到被全局异常捕获,那说明调用 ProcessCompleteListener.onE

    2024年02月06日
    浏览(44)
  • 【Spring】从Spring源码入手分析广播与监听并完成项目实战

    近期疫情形势严峻,情形不容乐观,周末也不敢出去浪了,躲在家里“葛优躺”。闲来无事,又翻了遍 Spring 的源码。不翻不知道,一翻吓一跳,之前翻过的源码已经吃进了肚子里,再见亦是陌生人。 个人建议:为了以后能快速的捡起某个知识点,最好的方法还是形成文档,

    2024年02月12日
    浏览(40)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包