Spring Source Reading 16: Inicializar emisores de eventos y registrar oyentes de eventos

Este es el día 30 de mi participación en el "Nuggets Daily New Plan·August Update Challenge", haz clic para ver los detalles del evento

Basado en Spring Framework v5.2.6.RELEASE

Continuación del artículo anterior: Código fuente de Spring, lectura 15: Inicializar MessageSource

Resumen

En el artículo anterior , ApplicationContext inicializa el contenedor Spring , se menciona que el AbstractApplicationContext#refreshmétodo es un método muy importante, que incluye todo el proceso de inicialización del contenedor Spring. Una serie de artículos recientes son un análisis en profundidad de los principios específicos de cada paso en este método. Este artículo luego analiza el proceso posterior, es decir refresh, estas líneas de código en el método:

// Initialize event multicaster for this context.
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
onRefresh();
// Check for listener beans and register them.
registerListeners();
复制代码

Inicializar el emisor de eventos

Mire initApplicationEventMulticasterprimero el método, como puede ver en el nombre del método, su función es inicializar la emisora ​​de tiempo.

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 {
      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() + "]");
      }
   }
}
复制代码

Esta lógica es similar a la lógica de inicialización de MessageSource presentada en el artículo anterior. Primero beanFactoryaverigüe si contiene applicationEventMulticasterel bean nombrado. Si hay uno, obténgalo y asígnelo a una applicationEventMulticastervariable miembro del contexto actual. De lo contrario, cree un SimpleApplicationEventMulticaster y asígnelo a una applicationEventMulticastervariable miembro y luego regístrelo beanFactory.

顺便简单介绍一下 Spring 的事件广播器。Spring 提供了一个基于事件(Event)的 Pub/Sub 机制,这个事件广播器存在与 Spring 的上下文当中。Spring 还有另外一个与此相关的组件叫做事件监听器(ApplicationListener),事件监听器作为 Bean 注册在 Spring 的容器中,每个事件监听器都有其监听的事件。当通过 Spring 的上下文发布一个事件之后,事件广播器就会获取到所有的事件监听器,并通知监听了这个事件的事件监听器。

本文的后半部分会详细介绍事件监听器,关于如何发布事件,也会在之后的文章介绍道。

空的onFresh方法

接下来看第二个方法调用,也就是onRefresh方法。

 /**
* Template method which can be overridden to add context-specific refresh work.
* Called on initialization of special beans, before instantiation of singletons.
* <p>This implementation is empty.
*  @throws  BeansException in case of errors
*  @see  #refresh()
*/
protected void onRefresh() throws BeansException {
   // For subclasses: do nothing by default.
}
复制代码

这是一个protected修饰的空模版方法,在方法的注释中,Spring 已经告诉我们它的作用,以及被调用的时机。这个方法在一些特定的 Bean 被实例化之后,普通的单例 Bean 初始化之前调用。子类可以继承这个方法来实现一些特定的逻辑。

这个方法属于 Spring 提供的扩展点。

注册事件监听器

最后看registerListeners方法。前面在初始化事件广播器的部分,已经介绍了事件监听器在整个事件广播相关环节的作用,这里有必要看一下事件监听器的具体代码。

@FunctionalInterface
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {

   /**
* Handle an application event.
*  @param  event the event to respond to
*/
void onApplicationEvent(E event);

}
复制代码

它是一个函数式接口,其中的onApplicationEvent方法用于处理事件。也就是说,事件广播器将事件通知给事件监听器,其实就是调用了onApplicationEvent方法。监听器需要实现这个方法,来定义监听到之间之后要执行的逻辑。

下面看它们是如何被注册的。

protected void registerListeners() {
   // Register statically specified listeners first.
   for (ApplicationListener<?> listener : getApplicationListeners()) {
      getApplicationEventMulticaster().addApplicationListener(listener);
   }

   // Do not initialize FactoryBeans here: We need to leave all regular beans
   // uninitialized to let post-processors apply to them!
   String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
   for (String listenerBeanName : listenerBeanNames) {
      getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
   }

   // Publish early application events now that we finally have a multicaster...
   Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
   this.earlyApplicationEvents = null;
   if (earlyEventsToProcess != null) {
      for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
         getApplicationEventMulticaster().multicastEvent(earlyEvent);
      }
   }
}
复制代码

注册事件监听器,其实就是把事件监听器添加到事件广播器的监听器列表中,因为,当有事件被发布的时候,是由事件广播器来通知事件监听器的。上面的代码,大体分为三个部分,我们分别来看:

  1. 首先,通过getApplicationListeners方法,将上下文的成员变量applicationListeners中的监听器注册到广播器中。
  1. 然后,通过getBeanNamesForType方法,从beanFactory中获取到所有 ApplicationListener 类型的 Bean 的名字,添加到广播器中。
  1. 最后,Spring 上下文的earlyApplicationEvents成员变量中保存了一些在事件广播器初始化之前就已经被发布,但是还未广播的事件,通过调用事件广播器的multicastEvent方法对其进行广播。

事件广播器是如何保存监听器的

以上步骤中的第一步是将监听器实例交给事件广播器,而第二步是将监听器的beanName交给事件监听器,这里有比要介绍一下事件监听器是如何处理的。

在事件广播器的内部,有一个 ListenerRetriever 类型的成员变量defaultRetriever,是在事件广播器被创建的时候就初始化的。

private final ListenerRetriever defaultRetriever = new ListenerRetriever(false);
复制代码

当有监听器被注册到事件广播器中的时候,实际上是交给了defaultRetriever。在defaultRetriever中,有两个集合类型的成员变量:

public final Set<ApplicationListener<?>> applicationListeners = new LinkedHashSet<>();
public final Set<String> applicationListenerBeans = new LinkedHashSet<>();
复制代码

它们分别保存着已经被实例化的监听器对象和未被初始化的监听器的beanName。当事件广播器需要获取所有监听器的时候,ListenerRetriever 就回使用applicationListenerBeans中保存的beanName把所有的实例都获取到,在跟applicationListeners中的所有实例合并一起返回。

事件是如何被广播的

分析完这个问题,再看一下事件广播器是如何广播事件的,也就是multicastEvent的具体原理。

@Override
public void multicastEvent(ApplicationEvent event) {
   multicastEvent(event, resolveDefaultEventType(event));
}

@Override
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);
      }
   }
}
复制代码

这里的逻辑很简单,先根据event获取到支持处理此类行事件的所有 ApplicationListener,然后通过invokeListener方法,执行监听器中的处理逻辑。

再进入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);
   }
}

@SuppressWarnings({"rawtypes", "unchecked"})
private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
   try {
      listener.onApplicationEvent(event);
   } catch (ClassCastException ex) {
      /* 省略异常处理的逻辑 */
   }
}
复制代码

El formato del código anterior se ha ajustado ligeramente. De hecho, el código central aquí es solo una línea, que es para llamar al onApplicationEventmétodo de escucha.

En este punto, se analiza esta parte del código.

hacer un seguimiento

Este artículo presenta principalmente la inicialización de las emisoras relacionadas con la transmisión de eventos y el registro de oyentes, y cómo se transmiten los eventos. En cuanto a cuándo la emisora ​​​​de eventos transmitirá un evento, habrá un proceso de publicación de eventos en el siguiente viaje. Por lo tanto, para Más adelante daré una introducción detallada. Posteriormente, continuaremos analizando el código de inicialización del contenedor Spring.

Guess you like

Origin juejin.im/post/7135650550506979359