zl程序教程

您现在的位置是:首页 >  后端

当前栏目

Springboot事件监听机制:工作原理

SpringBoot事件原理 机制 工作 监听
2023-09-14 09:04:52 时间

目录

前言

1.观察者模式

1.1观察者模式的核心元素

1.2观察者模式的工作流程

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

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

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

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

3.总结


前言

        这是继《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事件发布器是什么时候在哪里产生的呢?

        事件发布器实例化的入口AbstractApplicationContext#refresh中调用了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事件监听器是什么时候怎么注册到事件发布器里去了呢

        事件监听器注册到事件发布器里的逻辑在这个方法:AbstractApplicationContext#registerListeners,而registerListeners()也是在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<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
   this.earlyApplicationEvents = null;
   if (!CollectionUtils.isEmpty(earlyEventsToProcess)) {
      for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
         getApplicationEventMulticaster().multicastEvent(earlyEvent);
      }
   }
}

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

        顺着UserService#registe()里的this.applicationEventPublisher.publishEvent(),使劲往里面找,最后找到了AbstractApplicationContext#publishEvent(java.lang.Object),到这感觉出来点啥没,所有的逻辑都指向AbstractApplicationContext类,这里先按下不表,继续往下找事件是发布到哪了,最后在AbstractApplicationContext#publishEvent(Object, 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 necessary
   ApplicationEvent 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 initialized
   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);
      }
   }
}

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

沉住气,继续向里面翻SimpleApplicationEventMulticaster#multicastEvent(ApplicationEvent, 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事件监听器注册到事件发布器都是在AbstractApplicationContext#refresh()里完成,了解spring bean的生命周期的小伙伴,对这个方法肯定不陌生,这可是spring容器启动的灵魂,因此玩好spring,bean的生命周期必须玩透。到这里spring事件监听机制的工作原理基本摸清楚了,很多关键的事情,如事件发布器的实例化、事件监听器的注册这些都在spring容器启动的时候就开始了。这些关系理清楚后,才突然发现:真的是大道至简,牛逼就是简单,简单就是牛逼,致敬spring!