Spring 源码阅读 18:Spring 上下文初始化的最后一步
基于 Spring Framework v5.2.6.RELEASE
前情提要
在之前的 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);
}
}
}
这里的流程主要分三步:
- 先判断事件是不是 ApplicationEvent 的实例,之前流程中创建的 ContextRefreshedEvent 实现了 ApplicationEvent 接口,因此这里判断条件结果为
true
。 - 看事件广播站是不是已经初始化了。如果没有,就将当前时间添加到
earlyApplicationEvents
集合中,待事件广播器初始化之后再广播。如果初始化了,就调用multicastEvent
方法对事件进行广播。multicastEvent
方法的流程,之前介绍过了,可以参考:Spring 源码阅读 16:初始化事件广播器 & 注册事件监听器 。 - 如果当前上下文存在父级上下文,则在父级上下文中发布事件。
更多
最后一个步骤:
LiveBeansView.registerApplicationContext(this);
将 Spring 容器注册到 LiveBeansView 中,这部分不在我们讨论范围之内。
后续
Spring 容器初始化的流程到此就分析完了,一共写了 18 篇文章。后续将分析 Spring 初始化 Bean 的过程,会从我们已经见过很多次的getBean
方法入手,敬请期待。
转载自:https://juejin.cn/post/7135994676632354847