spring源码:Spring监听器实现原理

一、前言

  Spring中的监听器是一个典型的观察者模式,谈到观察者模式就一定有一个观察者被观察者。Spring中监听器的设计如下:

  • 观察者:ApplicationListener监听器
  • 被观察者:ApplicationEventMulticaster事件多播器

还不会使用Spring监听器的同学,先移步《spring监听器的使用》这篇文章。

二、原理

Spring使用事件多播器ApplicationEventMulticaster注册通知监听器。

先来看下刷新Application上下文的经典代码:

	public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			// 1. 准备刷新的上下文环境
			prepareRefresh();

			// 2. 初始化BeanFactory,并进行XML文件的加载
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// 3. 对BeanFactory进行各种功能填充
			prepareBeanFactory(beanFactory);

			try {
				// 4. 子类覆盖犯法做额外的处理
				postProcessBeanFactory(beanFactory);

				// 5. 调用BeanFactory后处理器
				invokeBeanFactoryPostProcessors(beanFactory);

				// 6. 注册bean后处理器,在调用getBean的时候回调这些bean后处理器的方法
				registerBeanPostProcessors(beanFactory);

				// 7. 为上下文初始化Message源
				initMessageSource();

				// 8. 初始化事件多播器
				initApplicationEventMulticaster();

				// 9. 留给子类初始化其他bean
				onRefresh();

				// 10. 注册监听器
				registerListeners();

				// 11. 初始化剩下的单例Bean(非惰性的)
				finishBeanFactoryInitialization(beanFactory);

				// 12. 最后一步,发布通知事件
				finishRefresh();
			}

			catch (BeansException ex) {
				if (logger.isWarnEnabled()) {
					logger.warn("Exception encountered during context initialization - " +
							"cancelling refresh attempt: " + ex);
				}

				// 销毁已经创建的单例,以避免挂起资源。
				destroyBeans();

				// Reset 'active' flag.
				cancelRefresh(ex);

				// Propagate exception to caller.
				throw ex;
			}

			finally {
				// Reset common introspection caches in Spring's core, since we
				// might not ever need metadata for singleton beans anymore...
				resetCommonCaches();
			}
		}
	}

这段代码是AbstractApplicationContext类的refresh方法,看Spring源码必读的方法!跟Spring监听器相关的逻辑,在第8步(初始化事件多播器)和第10步(注册监听器),我们展开分析下~

1. 初始化事件多播器
	public static final String APPLICATION_EVENT_MULTICASTER_BEAN_NAME = "applicationEventMulticaster";
	
	protected void initApplicationEventMulticaster() {
		ConfigurableListableBeanFactory beanFactory = getBeanFactory();
		// 1. bean工厂中如果有用户定义的applicationEventMulticaster的bean实例,则使用用户的事件多播器
		if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
			this.applicationEventMulticaster =
					beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
			if (logger.isDebugEnabled()) {
				logger.debug("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
			}
		}
		else {
			// 2. 否则使用默认的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 + "]");
			}
		}
	}

该代码片段在AbstractApplicationContext类的initApplicationEventMulticaster方法。如果用户没有定义自己的ApplicationEventMulticaster,就是使用Spring默认的事件多播器:SimpleApplicationEventMulticaster
可以看到,这个事件多播器保存在AbstractApplicationContext类的applicationEventMulticaster属性中。

2. 注册监听器

事件多播器初始化完成之后,就需要把容器中的监听器注册到这个事件多播器中了。

	protected void registerListeners() {
		// 1. 首先注册静态指定的监听器
		for (ApplicationListener<?> listener : getApplicationListeners()) {
			getApplicationEventMulticaster().addApplicationListener(listener);
		}

		// 2. 保存ApplicationListener类型的beanName
		String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
		for (String listenerBeanName : listenerBeanNames) {
			getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
		}

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

第2步有点不对啊,为什么只把ApplicationListener类型的beanName放到多播器中了,应该保存bean实例啊。Spring的注释中写到:我们需要保持所有常规bean未初始化,以便让后处理器应用于它们!
其实真正注册监听器的地方在ApplicationListenerDetector类中,ApplicationListenerDetector是一个Bean后处理器。容器中的Bean初始化之后,会调用Bean后处理器的postProcessAfterInitialization方法。我们来看下ApplicationListenerDetector类的postProcessAfterInitialization方法:

	public Object postProcessAfterInitialization(Object bean, String beanName) {
		// 如果这个bean实例是监听器类型
		if (bean instanceof ApplicationListener) {
			Boolean flag = this.singletonNames.get(beanName);
			if (Boolean.TRUE.equals(flag)) {
				// 注册ApplicationListener类型的bean实例,看下这个方法
				this.applicationContext.addApplicationListener((ApplicationListener<?>) bean);
			}
			else if (Boolean.FALSE.equals(flag)) {
				if (logger.isWarnEnabled() && !this.applicationContext.containsBean(beanName)) {
					// inner bean with other scope - can't reliably process events
					logger.warn("Inner bean '" + beanName + "' implements ApplicationListener interface " +
							"but is not reachable for event multicasting by its containing ApplicationContext " +
							"because it does not have singleton scope. Only top-level listener beans are allowed " +
							"to be of non-singleton scope.");
				}
				this.singletonNames.remove(beanName);
			}
		}
		return bean;
	}

如果bean是ApplicationListener类型,则调用AbstractApplicationContext类的addApplicationListener方法:

	public void addApplicationListener(ApplicationListener<?> listener) {
		Assert.notNull(listener, "ApplicationListener must not be null");
		if (this.applicationEventMulticaster != null) {
			// 把监听器注册到多播器中
			this.applicationEventMulticaster.addApplicationListener(listener);
		}
		else {
			this.applicationListeners.add(listener);
		}
	}

终于看到多播器了,最终监听器还是注册在多播器中的。

其实也不是多播器来直接管理监听器的,而是AbstractApplicationEventMulticaster多播器中有一个ListenerRetriever内部类。监听器保存在ListenerRetriever类的applicationListeners属性中。即:AbstractApplicationEventMulticaster.defaultRetriever.applicationListeners

3. 发布事件

我们一般使用AbstractApplicationContext类publishEvent方法来发布一个事件,其底层会调用SimpleApplicationEventMulticaster多播器multicastEvent方法。看下代码:

	public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
		// 1. 解析事件类型
		ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
		// 2. 循环通知监听器
		for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
			Executor executor = getTaskExecutor();
			if (executor != null) {
				executor.execute(() -> invokeListener(listener, event));
			}
			else {
				// 调用监听器方法
				invokeListener(listener, event);
			}
		}
	}

继续跟进去,SimpleApplicationEventMulticaster类的invokeListener方法

	protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
		ErrorHandler errorHandler = getErrorHandler();
		if (errorHandler != null) {
			try {
				// 真正的逻辑
				doInvokeListener(listener, event);
			}
			catch (Throwable err) {
				errorHandler.handleError(err);
			}
		}
		else {
			doInvokeListener(listener, event);
		}
	}

又是doXxx类型的方法在干活儿,继续点进去吧

	private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
		try {
			// 调用监听器的onApplicationEvent方法
			listener.onApplicationEvent(event);
		}
		catch (ClassCastException ex) {
			String msg = ex.getMessage();
			if (msg == null || matchesClassCastMessage(msg, event.getClass().getName())) {
				// 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;
			}
		}
	}

至此我们已经看到,最终是SimpleApplicationEventMulticaster多播器调用了监听器的onApplicationEvent方法,进而执行用户自定义的监听逻辑。

  • 6
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值