SpringFramework事件与监听机制(发布器)

本文通过SpringBoot项目的运行,来探讨Spring事件与监听机制,与上文《SpringBoot事件与监听机制》存在关联性,该文提出的疑问将在本文作出回答。本文除了探讨Spring事件与监听机制,也会尽最大努力与运行中的SpringBoot的事件与监听机制一并分析,揭开他们的关系。SpringBoot版本:2.0.2.RELEASESpring版本:5.0.6.RELEASE文章目录Spring事件与监听机制Spring的事件Spring与SpringBoot的事件关系类定义层面的关系发布事件的
摘要由CSDN通过智能技术生成

SpringBoot版本:2.0.2.RELEASE
SpringFramework版本:5.0.6.RELEASE

谁是SpringFramework的事件发布器

在这里插入图片描述从UML图看,ApplicationEventPublisher只声明了发布事件的方法,到了ConfigurableApplicationContext才补充了与监听器关联的方法。这些方法最终由AbstractApplicationContext实现。而它的子类一般也没有重载这些方法。因此,从类定义的角度来看,AbstractApplicationContext承担了发布事件的责任。
那么在一个SpringBoot工程里,它是如何成为事件发布者呢?在前文多处已经暗示,有一个发布器移交的这么一个过程,详见EventPublishingRunListener的各发布事件方法。
在SpringApplication#run方法的整体过程控制下,在SpringBoot发布ApplicationPreparedEvent事件的时候,有个将SpringBoot自己的Listener添加到ConfigurableApplicationContext的动作。然后AbstractApplicationContext#refresh方法会被调用,在该方法里完成了加载SpringFramework的监听器和初始化了SpringFramework层面的事件发布器SimpleApplicationEventMulticaster,最后调用finishRefresh方法发布ContextRefreshedEvent事件。下面列出AbstractApplicationContext#refresh方法内重点函数:

@Override
public void refresh() throws BeansException, IllegalStateException {
   
	....
	// Prepare the bean factory for use in this context.
	prepareBeanFactory(beanFactory);
	....
	// Initialize event multicaster for this context.
	initApplicationEventMulticaster();
	....
	// Check for listener beans and register them.
	registerListeners();
	....
	// Last step: publish corresponding event.
	finishRefresh();
}

这些函数不难,读者可自行翻阅。但有一点要注意的整个SpringBoot启动过程中,事件发布的顺序,以及在发布各个事件的时候系统为此做了什么准备工作。控制着这些节奏的其实是SpringApplication,在它的run方法里已经编好了整个大纲。

双子座的消息发布者

在《SpringBoot事件与监听机制》已经知道SpringBoot的事件发布器是EventPublishingRunListener,而它最终是委托SimpleApplicationEventMulticaster的来完成事件的发布。
在EventPublishingRunListener#contextLoaded方法看到为发点布器交棒的准备,在started和running方法,已经看到发布事件的工作交给了ConfigurableApplicationContext去完成。我们回头看contextLoaded方法,只是将SpringBoot的监听器添加到ConfigurableApplicationContext,但并没有将自己的SimpleApplicationEventMulticaster交过去,那么ConfigurableApplicationContext是用什么来发布信息呢?
在AbstractApplicationContext里我们看到ApplicationEventMulticaster接口类型属性的声明:

/** Helper class used in event publishing */
	@Nullable
	private ApplicationEventMulticaster applicationEventMulticaster;

在AbstractApplicationContext#refresh方法里会调用initApplicationEventMulticaster函数,里面就对该变量进行赋值:

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.isDebugEnabled()) {
   
				logger.debug("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
			}
		}
		else {
   
			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也有一个SimpleApplicationEventMulticaster作为自己的属性,名字叫applicationEventMulticaster。
我们再来观察AbstractApplicationContext是如何发布事件的,我们从publishEvent(ApplicationEvent event)方法开始跟踪,然后会来到publishEvent(Object event, @Nullable ResolvableType eventType)方法:

protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
   
		....
		if (this.earlyApplicationEvents != null) {
   
			this.earlyApplicationEvents.add(applicationEvent);
		}
		else {
   
			getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
		}

		// Publish event via parent context as well...
		if (this.parent != null) {
   
			if (this.parent instanceof AbstractApplicationContext) {
   
				((AbstractApplicationContext) this.parent).publishEvent(event, eventType);
			}
			else {
   
				this.parent.publishEvent(event);
			}
		}
	}

getApplicationEventMulticaster方法如下:

ApplicationEventMulticaster getApplicationEventMulticaster() throws IllegalStateException {
   
		if (this.applicationEventMulticaster == null) {
   
			throw new IllegalStateException("ApplicationEventMulticaster not initialized - " +
					"call 'refresh' before multicasting events via the context: " + this);
		}
		return this.applicationEventMulticaster;
	}

到这里就明白了,SpringFramwork最终也是用SimpleApplicationEventMulticaster来发布事件,但此SimpleApplicationEventMulticaster并不是SpringBoot的SimpleApplicationEventMulticaster。那么这样的话会产生什么效果呢?前文已多次讲到在AbstractApplicationContext#refresh方法执行前,在EventPublishingRunListener#contextLoaded方法里已经将SpringBoot监听器添加给ConfigurableApplicationContext(即AbstractApplicationContext),所以后续SpringBoot委托AbstractApplicationContext发布的任何事件,SpringBoot的监听器都有可能会收到(“有可能”是因为还有事件类型以及事件源类型匹配的问题在里面)。
从EventPublishingRunListener各发布事件的方法看来,SpringBoot层面的SimpleApplicationEventMulticaster只是起到临时发布事件的作用,在ConfigurableApplicationContext未完成refresh前,SpringBoot启动经历的各状态先由SpringBoot层面的SimpleApplicationEventMulticaster发布事件。当ConfigurableApplicationContext完成refresh后,就交由它去完成发布事件的工作。那么为什么SpringBoot不把自己的EventPublishingRunListener传给ConfigurableApplicationContext呢?其实在SpringBoot1.x版本里确实是这样做的,到了2.x版本就调整成现在这样。为什么有这个调整,我猜SpringBoot毕竟是基于Spri

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值