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

本文详细解读了Spring 5中事件监听机制的实现原理,通过观察者模式剖析ApplicationEvent、ApplicationEvent监听者和ApplicationEventMulticaster的角色,以及工作流程,包括源码中的关键步骤如初始化多播器、注册监听器和异步事件发布。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


在这里插入图片描述


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()

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()

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(默认同步)

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)

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,因此,事件监听器对事件的处理,是同步进行的。

在这里插入图片描述

来看看

在这里插入图片描述

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);

在这里插入图片描述


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小小工匠

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值