Spring 源码阅读 18:Spring 上下文初始化的最后一步

这是我参与「掘金日新计划 · 8 月更文挑战」的第31天,点击查看活动详情

基于 Spring Framework v5.2.6.RELEASE

接上篇:Spring 源码阅读 17:初始化非懒加载的单例 Bean

前情提要

在之前的 ApplicationContext 初始化 Spring 容器 一文中,提到 AbstractApplicationContext#refresh 方法是一个非常重要的方法,它包含了 Spring 容器初始化的整个流程。最近的一系列文章都在深入分析这个方法中的每一个步骤的具体原理,本文接着分析 最后的一步流程,也就是refresh方法中最后代码:

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

初始化的最后阶段

方法的代码如下:

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

几行方法调用,我们逐个来分析。

第一行,调用clearResourceCaches方法的作用主要是为了清除资源加载的缓存。接着往下看。

Spring 的生命周期

接下来的两行代码,跟 Spring 的生命周期有关。

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

首先初始化了 LifecycleProcessor,代码如下:

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

首先判断容器中是否包含了置顶名称的 Bean,如果有的话,就获取到并赋值给当前上下文的lifecycleProcessor成员变量。

如果没有的话,就创建一个 DefaultLifecycleProcessor 类型的defaultProcessor,赋值给lifecycleProcessor,并注册到容器中。

到这里就初始化完成了,跟之前很多 Spring 中特殊的 Bean 的初始化过程类似。

接下来看getLifecycleProcessor().onRefresh()这行代码。

getLifecycleProcessor方法其实就是从lifecycleProcessor成员变量获取了刚才初始化好的 LifecycleProcessor,我们直接看它的onRefresh方法。

@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. 看事件广播站是不是已经初始化了。如果没有,就将当前时间添加到earlyApplicationEvents集合中,待事件广播器初始化之后再广播。如果初始化了,就调用multicastEvent方法对事件进行广播。multicastEvent方法的流程,之前介绍过了,可以参考:Spring 源码阅读 16:初始化事件广播器 & 注册事件监听器
  3. 如果当前上下文存在父级上下文,则在父级上下文中发布事件。

更多

最后一个步骤:

LiveBeansView.registerApplicationContext(this);
复制代码

将 Spring 容器注册到 LiveBeansView 中,这部分不在我们讨论范围之内。

后续

Spring 容器初始化的流程到此就分析完了,一共写了 18 篇文章。后续将分析 Spring 初始化 Bean 的过程,会从我们已经见过很多次的getBean方法入手,敬请期待。

猜你喜欢

转载自juejin.im/post/7135994676632354847
今日推荐