Lectura 18 del código fuente de Spring: el paso final de la inicialización del contexto de Spring

Este es el día 31 de mi participación en el "Nuevo plan diario de Nuggets · Desafío de actualización de agosto", haga 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 17: Inicializar beans singleton cargados no perezosos

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 último paso del proceso, es decir refresh, el último código en el método:

// Last step: publish corresponding event.
finishRefresh();
复制代码

etapa final de inicialización

El código del método es el siguiente:

protected void finishRefresh() {
   // Clear context-level resource caches (such as ASM metadata from scanning).
   clearResourceCaches();
   // Initialize lifecycle processor for this context.
   initLifecycleProcessor();
   // Propagate refresh to lifecycle processor first.
   getLifecycleProcessor().onRefresh();
   // Publish the final event.
   publishEvent(new ContextRefreshedEvent(this));
   // Participate in LiveBeansView MBean, if active.
   LiveBeansView.registerApplicationContext(this);
}
复制代码

Varias líneas de llamadas a métodos, analicémoslas una por una.

La primera línea, la función de llamar al método clearResourceCaches es principalmente para borrar el caché de la carga de recursos. Luego mira hacia abajo.

ciclo de vida de la primavera

Las siguientes dos líneas de código están relacionadas con el ciclo de vida de Spring.

// Initialize lifecycle processor for this context.
initLifecycleProcessor();
// Propagate refresh to lifecycle processor first.
getLifecycleProcessor().onRefresh();
复制代码

Primero inicialice LifecycleProcessor, el código es el siguiente:

protected void initLifecycleProcessor() {
   ConfigurableListableBeanFactory beanFactory = getBeanFactory();
   if (beanFactory.containsLocalBean(LIFECYCLE_PROCESSOR_BEAN_NAME)) {
      this.lifecycleProcessor =
            beanFactory.getBean(LIFECYCLE_PROCESSOR_BEAN_NAME, LifecycleProcessor.class);
      if (logger.isTraceEnabled()) {
         logger.trace("Using LifecycleProcessor [" + this.lifecycleProcessor + "]");
      }
   }
   else {
      DefaultLifecycleProcessor defaultProcessor = new DefaultLifecycleProcessor();
      defaultProcessor.setBeanFactory(beanFactory);
      this.lifecycleProcessor = defaultProcessor;
      beanFactory.registerSingleton(LIFECYCLE_PROCESSOR_BEAN_NAME, this.lifecycleProcessor);
      if (logger.isTraceEnabled()) {
         logger.trace("No '" + LIFECYCLE_PROCESSOR_BEAN_NAME + "' bean, using " +
               "[" + this.lifecycleProcessor.getClass().getSimpleName() + "]");
      }
   }
}
复制代码

Primero, determine si el contenedor contiene el bean con el nombre superior y, de ser así, obténgalo y asígnelo a la lifecycleProcessorvariable miembro del contexto actual.

De lo contrario, cree un tipo DefaultLifecycleProcessor defaultProcessor, asígnelo a lifecycleProcessory regístrelo con el contenedor.

Aquí se completa la inicialización, que es similar al proceso de inicialización de muchos beans especiales en Spring.

A continuación, observe getLifecycleProcessor().onRefresh()esta línea de código.

getLifecycleProcessorEl método es en realidad para lifecycleProcessorobtener el LifecycleProcessor que se acaba de inicializar de la variable miembro Veamos su onRefreshmétodo directamente.

@Override
public void onRefresh() {
   startBeans(true);
   this.running = true;
}

private void startBeans(boolean autoStartupOnly) {
   Map<String, Lifecycle> lifecycleBeans = getLifecycleBeans();
   Map<Integer, LifecycleGroup> phases = new HashMap<>();
   lifecycleBeans.forEach((beanName, bean) -> {
      if (!autoStartupOnly || (bean instanceof SmartLifecycle && ((SmartLifecycle) bean).isAutoStartup())) {
         int phase = getPhase(bean);
         LifecycleGroup group = phases.get(phase);
         if (group == null) {
            group = new LifecycleGroup(phase, this.timeoutPerShutdownPhase, lifecycleBeans, autoStartupOnly);
            phases.put(phase, group);
         }
         group.add(beanName, bean);
      }
   });
   if (!phases.isEmpty()) {
      List<Integer> keys = new ArrayList<>(phases.keySet());
      Collections.sort(keys);
      for (Integer key : keys) {
         phases.get(key).start();
      }
   }
}
复制代码

这里的逻辑简单概括就是,从容器中获取所有实现了 Lifecycle 接口的 Bean,然后调用他们的start方法。

最后还有必要介绍一下刚才提到的几个接口和类型。以下是他们的关系图。

Lifecycle 顾名思义就是生命周期的意思,接口中定义了一系列方法,实现了这个接口的 Bean,会在 Spring 生命周期的特定阶段被调用相依的方法。

比如,在刚刚的介绍中,所有实现了 Lifecycle 的 Bean 会在 Spring 上下文启动时调用start也就意味着,这些 Bean 的start方法中的逻辑会在 Spring 上下文启东时被执行。LifecycleProcessor 接口在此基础上,添加了两个生命周期方法。其中就包括刚刚分析的代码中被调用的onRefresh方法。

事件发布

接着看后面的步骤:

publishEvent(new ContextRefreshedEvent(this));
复制代码

这里调用了publishEvent方法,发布了一个 ContextRefreshedEvent 事件。事件发布之后,事件广播器就会将这个事件广播给所有要处理这个事件的监听器,执行其中的onApplicationEvent方法。

关于事件广播器的原理、事件监听器的注册、以及事件广播的过程,在之前的源码分析中已经介绍过了,这里不再详细介绍,可以参考:Spring 源码阅读 16:初始化事件广播器 & 注册事件监听器

这里主要从publishEvent方法的源码中分析一下事件发布的原理。

@Override
public void publishEvent(ApplicationEvent event) {
   publishEvent(event, null);
}

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

这里的流程主要分三步:

  1. 先判断事件是不是 ApplicationEvent 的实例,之前流程中创建的 ContextRefreshedEvent 实现了 ApplicationEvent 接口,因此这里判断条件结果为true
  2. Vea si la estación de transmisión de eventos se ha inicializado. De lo contrario, agregue la hora actual a la earlyApplicationEventscolección y espere a que el transmisor de eventos se inicialice antes de transmitir. Si se inicializa, se llama al método multicastEventpara transmitir el evento. multicastEventEl proceso del método se ha presentado antes, puede consultar: Código fuente de Spring, lectura 16: Inicialice el emisor de eventos y registre el oyente de eventos .
  3. Si existe un contexto principal para el contexto actual, el evento se publica en el contexto principal.

Más

Último paso:

LiveBeansView.registerApplicationContext(this);
复制代码

Registrar el contenedor Spring con LiveBeansView está fuera de nuestro alcance.

hacer un seguimiento

En este punto se ha analizado el proceso de inicialización del contenedor Spring y se han escrito un total de 18 artículos. En el seguimiento, analizaremos el proceso de inicialización de beans de Spring, getBeancomenzando con los métodos que hemos visto muchas veces, así que estad atentos.

Supongo que te gusta

Origin juejin.im/post/7135994676632354847
Recomendado
Clasificación