Spring source code reading 18: The final step of Spring context initialization

This is the 31st day of my participation in the "Nuggets Daily New Plan · August Update Challenge", click to view the details of the event

Based on Spring Framework v5.2.6.RELEASE

Continued from the previous article: Spring source code reading 17: Initialize non-lazy loaded singleton beans

Recap

In the previous article, ApplicationContext initializes the Spring container , it is mentioned that the AbstractApplicationContext#refreshmethod is a very important method, which includes the entire process of the Spring container initialization. A series of recent articles are in-depth analysis of the specific principles of each step in this method. This article then analyzes the last step of the process, that is refresh, the last code in the method:

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

final stage of initialization

The code for the method is as follows:

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

Several lines of method calls, let's analyze them one by one.

The first line, the function of calling the clearResourceCaches method is mainly to clear the cache of resource loading. Then look down.

Spring's life cycle

The next two lines of code are related to Spring's life cycle.

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

First initialize LifecycleProcessor, the code is as follows:

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

First, determine whether the container contains the bean with the top name. If so, get it and assign it to the lifecycleProcessormember variable of the current context.

If not, create a DefaultLifecycleProcessor type defaultProcessor, assign it to lifecycleProcessor, and register it with the container.

The initialization is completed here, which is similar to the initialization process of many special beans in Spring.

Next look at getLifecycleProcessor().onRefresh()this line of code.

getLifecycleProcessorThe method is actually to lifecycleProcessorget the LifecycleProcessor that was just initialized from the member variable. Let's look at its onRefreshmethod directly.

@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. See if the event broadcast station has been initialized. If not, add the current time to the earlyApplicationEventscollection and wait for the event broadcaster to initialize before broadcasting. If initialized, the method is called multicastEventto broadcast the event. multicastEventThe process of the method has been introduced before, you can refer to: Spring source code reading 16: Initialize the event broadcaster & register the event listener .
  3. If a parent context exists for the current context, the event is published in the parent context.

More

Last step:

LiveBeansView.registerApplicationContext(this);
复制代码

Registering the Spring container with LiveBeansView is beyond our scope.

follow-up

The process of Spring container initialization has been analyzed at this point, and a total of 18 articles have been written. In the follow-up, we will analyze the process of Spring's initialization of beans, getBeanstarting with the methods we have seen many times, so stay tuned.

Guess you like

Origin juejin.im/post/7135994676632354847