springboot事件监听机制二:基本工作原理
创始人
2024-03-24 18:56:12
0

前言

        这是继《springboot事件监听机制一:实战应用》第二篇,知其然,当然还要知其所以然,深入的源码里面探寻一下这一有套机制的工作原理。spring生态很茂盛,这里不会站太高去分析这个问题,大扯spring的一些原理,而是以一个求知者的心态去探索spring监听机制的秘密,可能我分析得并不透彻,但我想如果能给看到这篇文章的你带去一些灵感或者触动也是好的。罗马不是一天就能建立起来的,想要弄懂它也非一天的事,多想多看总会明白的。另外看源码的时候,一定是带着问题去探寻,时刻把握好问题的核心,切忌被旁枝末节打扰而迷失的源码里了(如果对一旁枝末节实在很感兴趣,可以先记录下来位置,之后再来探寻)。发现问题,然后解决问题,这就是进步!现在一起来进步吧!

1.观察者模式

1.1观察者模式的核心元素

 springboot事件监听机制的原理是观察者模式,观察者模式有几个核心的元素:

  •         事件源
  •         事件
  •         事件发布器
  •         监听器

1.2观察者模式的工作流程

  1.         事件监听器注册到事件发布器,用于监听事件
  2.         事件源产生事件,然后向发布器发布事件,
  3.         事件发布器回调已注册的监听器的回调方法
  4.         事件监听器的回调方法被调用

2.springboot事件监听机制的基本工作原理

        正如上一篇文章中的示例,把各业务中的短信发送需求抽象成一个短信发事件,在各业务需要发送短信的时候,就通过事件发布器来发布事件,然后触发短信发送监听器里的发送短信操作一样,Spring生态这么庞大,功能也多,自身的事件自不会少,如容器启动、容器刷新、关闭、停止等都是一个事件。为什么会这样呢?这是因为Spring容器在初始化、启动、刷新、关闭等这些过程中,也需要通知其他模块,所以spring自身也有很多事件也就不奇怪了。 但是这么多事件,功能不一样,但是本质是相同的,所有事件一基类都是java.util.EventObject。所以下面还是以上一篇文章中的短信发布事件作为例子,来探寻一下springboot的事件监听的工作原理。

         在上一篇的例子中,封装好短信事件,同是也把短信监听器通过@component注解注册到了spring容器里,然后就在业务中直接通过事件发布器(ApplicationEventPublisher)发布了,这中间许多细节是什么样的呢?比如:

  • 事件发布器是什么时候在哪里产生的呢?
  • 事件监听器是什么时候什么注册到事件发布里去了呢
  • 事件发布器发布事件后,是怎么执行的监听器的回调方法了呢?

2.1事件发布器是什么时候在哪里产生的呢?

        事件发布器实例化的入口org.springframework.context.support.AbstractApplicationContext#refresh中调用了org.springframework.context.support.AbstractApplicationContext#initApplicationEventMulticaster,最后实际会实例出一个SimpleApplicationEventMulticaster对象,这个对象一般都翻译成事件广播器,他的作用就是发布事件、接受监听器的注册、回调监听器中的回调方法。眼尖的人都看出来了,在业务类里注册的事件发布器是ApplicationEventPublisher,不是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 {//spring容器启动的时候,applicationEventMulticaster还没有创立,会走这里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() + "]");}}
}

2.2事件监听器是什么时候怎么注册到事件发布器里去了呢

        事件监听器注册到事件发布器里的逻辑在这个方法:org.springframework.context.support.AbstractApplicationContext#registerListeners,而registerListeners()也是在org.springframework.context.support.AbstractApplicationContext#refresh()里被调用的

protected void registerListeners() {// Register statically specified listeners first.for (ApplicationListener listener : getApplicationListeners()) {getApplicationEventMulticaster().addApplicationListener(listener);}//smsListener通过@Component注册到spring容器里后,在这里注册到spring的事件广播器里String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);for (String listenerBeanName : listenerBeanNames) {getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);}Set earlyEventsToProcess = this.earlyApplicationEvents;this.earlyApplicationEvents = null;if (!CollectionUtils.isEmpty(earlyEventsToProcess)) {for (ApplicationEvent earlyEvent : earlyEventsToProcess) {getApplicationEventMulticaster().multicastEvent(earlyEvent);}}
}

2.3事件发布器发布事件后,发生了什么?是怎么执行的监听器的回调方法了呢?

        顺着com.example.springeventdemo.service.UserService#registe()里的this.applicationEventPublisher.publishEvent(),使劲往里面找,最后找到了org.springframework.context.support.AbstractApplicationContext#publishEvent(java.lang.Object),到这感觉出来点啥没,所有的逻辑都指向AbstractApplicationContext类,这里先按下不表,继续往下找事件是发布到哪了,最后在org.springframework.context.support.AbstractApplicationContext#publishEvent(java.lang.Object, org.springframework.core.ResolvableType)里找到了一句 getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType),顺着getApplicationEventMulticaster(),再往下找到spring的事件广播器接口ApplicationEventMulticaster,SimpleApplicationEventMulticaster是ApplicationEventMulticaster接口的实现类,这下明白在第一个问题中疑问了吧,表面上的事件发布器是ApplicationEventPublisher,而实际最终执行发布事件的是SimpleApplicationEventMulticaster。

protected void publishEvent(Object event, @Nullable ResolvableType eventType) {Assert.notNull(event, "Event must not be null");// Decorate event as an ApplicationEvent if necessaryApplicationEvent applicationEvent;if (event instanceof ApplicationEvent) {applicationEvent = (ApplicationEvent) event;}else {applicationEvent = new PayloadApplicationEvent<>(this, event);if (eventType == null) {eventType = ((PayloadApplicationEvent) applicationEvent).getResolvableType();}}// Multicast right now if possible - or lazily once the multicaster is initializedif (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);}}
}

        到这里,只是找到了通过this.applicationEventPublisher.publishEvent()找到了发布事件的实际干活人(SimpleApplicationEventMulticaster),它是怎么干活的呢?

沉住气,继续向里面翻org.springframework.context.event.SimpleApplicationEventMulticaster#multicastEvent(org.springframework.context.ApplicationEvent, org.springframework.core.ResolvableType)后,仔细看一下里面的逻辑:先看一下有没有线程池可用,如果有,就用,如果没有,就不用,直接执行监听器里的回调方法onApplicationEvent(),最后找到了SmsListener中具体执行发短信操作的onApplicationEvent();

public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));Executor executor = getTaskExecutor();for (ApplicationListener listener : getApplicationListeners(event, type)) {if (executor != null) {executor.execute(() -> invokeListener(listener, event));}else {invokeListener(listener, event);}}
}

3.总结

        Spring事件的发布器的实例化、Spring事件监听器注册到事件发布器、Spring事件的发布都指向一个类AbstractApplicationContext,其中Spring事件的发布器的实例化、Spring事件监听器注册到事件发布器都是在org.springframework.context.support.AbstractApplicationContext#refresh()里完成,了解spring bean的生命周期的小伙伴,对这个方法肯定不陌生,这可是spring容器启动的灵魂,因此玩好spring,bean的生命周期必须玩透。到这里spring事件监听机制的工作原理基本摸清楚了,很多关键的事情,如事件发布器的实例化、事件监听器的注册这些都在spring容器启动的时候就开始了。这些关系理清楚后,才突然发现:真的是大道至简,牛逼就是简单,简单就是牛逼,致敬spring!

相关内容

热门资讯

监控摄像头接入GB28181平... 流程简介将监控摄像头的视频在网站和APP中直播,要解决的几个问题是:1&...
Windows10添加群晖磁盘... 在使用群晖NAS时,我们需要通过本地映射的方式把NAS映射成本地的一块磁盘使用。 通过...
protocol buffer... 目录 目录 什么是protocol buffer 1.protobuf 1.1安装  1.2使用...
在Word、WPS中插入AxM... 引言 我最近需要写一些文章,在排版时发现AxMath插入的公式竟然会导致行间距异常&#...
Fluent中创建监测点 1 概述某些仿真问题,需要创建监测点,用于获取空间定点的数据࿰...
educoder数据结构与算法...                                                   ...
MySQL下载和安装(Wind... 前言:刚换了一台电脑,里面所有东西都需要重新配置,习惯了所...
MFC文件操作  MFC提供了一个文件操作的基类CFile,这个类提供了一个没有缓存的二进制格式的磁盘...
有效的括号 一、题目 给定一个只包括 '(',')','{','}'...
【Ctfer训练计划】——(三... 作者名:Demo不是emo  主页面链接:主页传送门 创作初心ÿ...