Spring IoC 源码解析:高级容器的初始化过程

前面的几篇文章我们一直围绕着 BeanFactory 分析容器的初始化和依赖注入过程,本篇我们将从 ApplicationContext 触发探究容器的高级形式。ApplicationContext 相对于 BeanFactory 扩展了许多实用功能,方便开发者的使用。二者的结构设计我们在前面的文章中已经介绍过,本篇将详细分析基于 ApplicationContext 的容器初始化和注入过程。

关于 ApplicationContext 的使用方式,广大开发者应该是信手拈来,这里还是简单的举例一下:

1
2
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:spring-core.xml");
MyBean myBean = (MyBean) context.getBean("myBean");

相对于 BeanFactory 来说,ApplicationContext 在使用方式上没有太大的区别,也是分成两步走:第一步加载配置;第二步执行 bean 实例的创建和初始化过程。其中,第二步与之前我们分析 BeanFactory 时的 BeanFactory#getBean 方法复用的是一套逻辑。

由前面文章介绍的继承关系我们知道,ApplicationContext 不是一个新的策略实现类,而是从 BeanFactory 扩展而来,并且将主要的精力都放在了对配置文件加载和解析层面。这样的实现也是很容易理解的,毕竟第一步是和开发者息息相关的,是开发者能够直接配置的东西,这一块的优化能够直观反映在框架的使用上,而第二步主要是框架内部的运作流程。所以接下来我们主要探究第一步的实现过程,而第二步则可以参考上一篇专门分析 bean 实例创建与初始化过程的文章。

第一步的逻辑暴露给开发者的接口位于 ClassPathXmlApplicationContext 类的构造方法中,我们通过 new ClassPathXmlApplicationContext("classpath:spring-core.xml") 触发高级容器加载和解析配置的逻辑,实现如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
this(new String[] {configLocation}, true, null);
}

public ClassPathXmlApplicationContext(
String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
throws BeansException {
super(parent);
// 支持多个配置文件以数组形式传入
this.setConfigLocations(configLocations);
if (refresh) {
// 加载配置,并初始化 IoC 容器
refresh();
}
}

Spring 定义了 AbstractRefreshableConfigApplicationContext#configLocation 数组用来记录传递的配置文件路径。因为允许传递多个配置文件,考虑配置文件的组织形式不一定是容器能够理解的方式,所以还需要执行一些解析的工作:

1
2
3
4
5
6
7
8
9
10
11
12
public void setConfigLocations(@Nullable String... locations) {
if (locations != null) {
Assert.noNullElements(locations, "Config locations must not be null");
this.configLocations = new String[locations.length];
// 遍历解析指定的路径,将占位符替换成具体的值
for (int i = 0; i < locations.length; i++) {
this.configLocations[i] = resolvePath(locations[i]).trim();
}
} else {
this.configLocations = null;
}
}

我们传递的配置文件路径可能存在一些占位符,所以容器需要对这些占位符进行解析,使用真实指代的值进行替换。

接下来,Spring 会调用 AbstractApplicationContext#refresh 方法初始化 IoC 容器,该方法是 ApplicationContext 的核心,概括了高级容器的整体初始化过程,实现如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 1. 初始化上下文环境
this.prepareRefresh();

// 2. 初始化 BeanFactory,加载并解析配置
ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();

// 3. 对 BeanFactory 进行功能增强
this.prepareBeanFactory(beanFactory);
try {
// 4. 模板方法,后置处理 BeanFactory 实例
this.postProcessBeanFactory(beanFactory);

// 5. 应用 BeanFactoryPostProcessor 处理器对 BeanFactory 实例进行后置处理
this.invokeBeanFactoryPostProcessors(beanFactory);

// 6. 注册 BeanPostProcessor 处理器,这里仅仅是注册,调用发生在 getBean 的时候
this.registerBeanPostProcessors(beanFactory);

// 7. 初始化国际化资源
this.initMessageSource();

// 8. 注册事件通知广播器
this.initApplicationEventMulticaster();

// 9. 模板方法
this.onRefresh();

// 10. 注册事件监听器
this.registerListeners();

// 11. 实例化非延迟加载的 singleton 类对象
this.finishBeanFactoryInitialization(beanFactory);

// 12. 完成 refresh 过程,发布事件通知
this.finishRefresh();
} catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + ex);
}

// Destroy already created singletons to avoid dangling resources.
this.destroyBeans();

// Reset 'active' flag.
this.cancelRefresh(ex);

// Propagate exception to caller.
throw ex;
} finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
this.resetCommonCaches();
}
}
}

高级容器的初始化整体流程可以概括为:

  1. 初始化上下文环境;
  2. 初始化 BeanFactory,加载并解析配置;
  3. 增强 BeanFactory,附加标准上下文特征;
  4. 后置处理 BeanFactory,这一过程交由子类实现,以提升容器的可扩展性;
  5. 后置处理 BeanFactory,应用 BeanFactoryPostProcessor 处理器;
  6. 注册 BeanPostProcessor 处理器;
  7. 初始化国际化资源;
  8. 注册事件通知广播器;
  9. 调用模板方法 AbstractApplicationContext#onRefresh,可以通过覆盖实现该方法扩展 refresh 流程;
  10. 向事件通知广播器中注册事件监听器;
  11. 实例化非延迟加载的 singleton 类对象;
  12. 完成刷新过程,发布事件通知。

其中步骤 1 和 2 已经完成了简单容器中解析配置文件、以 BeanDefinition 对象承载配置,并注册到容器的全部过程,从第 3 步开始进入属于高级容器的扩展实现。下面对上述步骤中的关键点展开分析。

初始化上下文环境

初始化上下文作为整个流程的第一步,包含了重置上下文状态、解析属性占位符,以及验证必要属性是否缺失等工作,由 AbstractApplicationContext#prepareRefresh 方法实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
protected void prepareRefresh() {
// Switch to active.
this.startupDate = System.currentTimeMillis();
this.closed.set(false);
// 标记当前上下文被激活
this.active.set(true);

// 模板方法,执行一些初始化操作,例如解析属性占位符
this.initPropertySources();

// Validate that all properties marked as required are resolvable: see ConfigurablePropertyResolver#setRequiredProperties
// 验证所有必要的属性是否都有配置
this.getEnvironment().validateRequiredProperties();

// Store pre-refresh ApplicationListeners...
if (this.earlyApplicationListeners == null) {
this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners);
} else {
// Reset local application listeners to pre-refresh state.
this.applicationListeners.clear();
this.applicationListeners.addAll(this.earlyApplicationListeners);
}

// 记录需要提前感知的应用事件 ApplicationEvent,一旦 multicaster 可用则会发布这些事件
this.earlyApplicationEvents = new LinkedHashSet<>();
}

对于一些必要的属性,如果缺失会影响系统的正常执行逻辑,对于这类属性可以调用 ConfigurablePropertyResolver#setRequiredProperties 方法将其设置为 required,这样在初始化上下文时就会校验其是否存在,如果不存在则会提前抛出异常。

创建并初始化 BeanFactory

ApplicationContext 是基于 BeanFactory 的扩展实现,复用了 BeanFactory 加载并解析配置文件的过程。所以在这一步,ApplicationContext 就已经完成了加载静态配置,并解析成为 BeanDefinition 对象注册到 IoC 容器的过程。这里的 BeanFactory 具体实现是 DefaultListableBeanFactory 类,前面曾强调过该类在 BeanFactory 的继承体系中占有着相当重要的地位,是 IoC 容器完整功能的一个基本实现。

基于 DefaultListableBeanFactory 创建并初始化 BeanFactory 的实现位于 AbstractApplicationContext#obtainFreshBeanFactory 方法中,实现如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
// 1. 初始化 BeanFactory,加载并解析配置,在这一步已经得到了 BeanDefinition 对象
this.refreshBeanFactory();
// 2. 返回 BeanFactory 对象
return this.getBeanFactory();
}

protected final void refreshBeanFactory() throws BeansException {
// 之前已经被 refresh 过,还没有被关闭,先执行关闭操作
if (this.hasBeanFactory()) {
// 销毁所有的 bean 实例
this.destroyBeans();
// 关闭 BeanFactory
this.closeBeanFactory();
}
try {
// 创建 BeanFactory 对象,基于 DefaultListableBeanFactory 实现类
DefaultListableBeanFactory beanFactory = this.createBeanFactory();
// 指定序列化 ID,必要的话可以反序列化得到 BeanFactory 对象
beanFactory.setSerializationId(this.getId());
/*
* 1. 是否允许配置同名称的 bean(后面的配置会覆盖前面的配置)
* 2. 是否允许循环依赖
*/
this.customizeBeanFactory(beanFactory);
// 加载并解析配置,由静态配置转为 BeanDefinition 对象
this.loadBeanDefinitions(beanFactory);
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
} catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + this.getDisplayName(), ex);
}
}

上述方法首先会判断是否已经有创建的 BeanFactory 实例存在,如果存在则说明上下文之前已经被 refresh 过,且没有正常关闭对应的 BeanFactory,所以再次被 refresh 之前需要执行关闭操作。接着,调用 AbstractXmlApplicationContext#loadBeanDefinitions 方法加载并解析配置。

如果看过本系列之前的文章,你一定会理解本方法的作用,并体会到其过程的复杂程度。该方法包含了获取配置文件 Document 对象、执行默认标签和自定义标签的解析,并最终将配置封装到 BeanDefinition 对象中返回的逻辑。经过这一系列步骤,XML 中静态的配置就会转变成内存中的数据结构 BeanDefinition 对象注册到 IoC 容器中。

为 BeanFactory 附加标准上下文特征

上面两个步骤已经完成了简单容器中加载并解析配置的功能,以此为分界线将开始对简单容器进行功能增强处理。增强的第一步就是调用 AbstractApplicationContext#prepareBeanFactory 方法为 BeanFactory 设置一些上下文所应该具备的标准特性,实现如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// 设置类加载器,用于加载 bean 对象
beanFactory.setBeanClassLoader(this.getClassLoader());
// 设置表达式解析器,以提供 EL 表达式风格的属性调用
beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
// 添加默认属性编辑器
beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, this.getEnvironment()));

/*
* 添加后置处理器 ApplicationContextAwareProcessor, 如果实现了如下相应的 Aware 接口,则注入对应的资源:
* 1. EnvironmentAware
* 2. EmbeddedValueResolverAware
* 3. ResourceLoaderAware
* 4. ApplicationEventPublisherAware
* 5. MessageSourceAware
* 6. ApplicationContextAware
*/
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
// 忽略以下接口的自动装配,即上面已经处理的 Aware 接口
beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);

// BeanFactory interface not registered as resolvable type in a plain factory.
// MessageSource registered (and found for autowiring) as a bean.
// 注册几个自动装配的规则
beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
beanFactory.registerResolvableDependency(ResourceLoader.class, this);
beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
beanFactory.registerResolvableDependency(ApplicationContext.class, this);

// 注册后置处理器 ApplicationListenerDetector,用于探测 ApplicationListener 类型接口
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));

// 增加对 AspectJ 的支持
if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
// Set a temporary ClassLoader for type matching.
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}

// 注册默认系统环境相关的 bean 实例
if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
// Environment
beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, this.getEnvironment());
}
if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
// System Properties
beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, this.getEnvironment().getSystemProperties());
}
if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
// System Environment
beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, this.getEnvironment().getSystemEnvironment());
}
}

上述实现为 BeanFactory 增加了如下上下文特性:

  1. 增加了对 Spring SpEL 表达式的支持。
  2. 添加属性编辑器,以实现对某些类型属性的统一处理。
  3. 自动装配 Aware 类,注入相应的资源。
  4. 自动探测 ApplicationListener 监听器类。
  5. 增加了对 AspectJ 的支持。
  6. 注册系统环境变量相关的 bean 实例,用于获取系统环境变量。

Spring Expression Language,即 SpEL 表达式是在 3.0 版本引入的新特性,允许我们在配置时候以类似 EL 表达式的方式引用上下文中的变量,未接触过的同学可以自己去体验一下。

  • 属性编辑器

执行属性注入时,如果希望对某一类型的属性执行一些处理,可以通过自定义属性编辑器 PropertyEditor 实现。典型的应用场景就是对时间类型属性的转换,假设某个 bean 实例存在 LocalDate 类型的属性,这个时候我们直接以字符串配置进行注入是会出错的,解决的方法就是通过自定义属性编辑器实现类型的转换,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class LocalDatePropertyEditor extends PropertyEditorSupport implements InitializingBean {

private String format = "yyyy-MM-dd";
private DateTimeFormatter formatter;

@Override
public void afterPropertiesSet() throws Exception {
formatter = DateTimeFormatter.ofPattern(format);
}

@Override
public void setAsText(String text) throws IllegalArgumentException {
if (StringUtils.hasText(text)) {
this.setValue(LocalDate.parse(text, formatter));
}
throw new IllegalArgumentException("illegal property: " + text);
}

public void setFormat(String format) {
this.format = format;
this.formatter = DateTimeFormatter.ofPattern(format);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
<!-- 注册自定义属性解析器 -->
<bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
<property name="customEditors">
<map>
<entry key="java.time.LocalDate">
<bean class="org.zhenchao.spring.ioc.LocalDatePropertyEditor">
<property name="format" value="yyyy-MM-dd"/>
</bean>
</entry>
</map>
</property>
</bean>

通过自定义属性编辑器 LocalDatePropertyEditor,基于时间格式化工具对指定格式的字符串日期进行转换和注入。上述转换只能在以 ApplicationContext 方式加载 bean 实例的前提下才生效,如果使用的是 BeanFactory 则还是会抛出异常,毕竟这属于高级容器中增强的功能。

  • Aware 特性处理

当定义的 bean 实现了 Aware 接口时,这些 bean 可以比一般的 bean 多拿到一些资源。ApplicationContext 对于 BeanFactory 的扩展增加了对一些 Aware 类自动装配支持。ApplicationContextAwareProcessor 实现了 BeanPostProcessor 接口,并主要覆盖实现了 ApplicationContextAwareProcessor#postProcessBeforeInitialization 方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
// 仅处理实现了指定接口的 bean 实例
if (!(bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)) {
return bean;
}

/* 调用 ApplicationContextAwareProcessor#invokeAwareInterfaces 方法为 bean 实例附加一些资源 */

AccessControlContext acc = null;

if (System.getSecurityManager() != null) {
acc = this.applicationContext.getBeanFactory().getAccessControlContext();
}

if (acc != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
this.invokeAwareInterfaces(bean);
return null;
}, acc);
} else {
this.invokeAwareInterfaces(bean);
}

return bean;
}

private void invokeAwareInterfaces(Object bean) {
// EnvironmentAware
if (bean instanceof EnvironmentAware) {
((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
}
// EmbeddedValueResolverAware
if (bean instanceof EmbeddedValueResolverAware) {
((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);
}
// ResourceLoaderAware
if (bean instanceof ResourceLoaderAware) {
((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
}
// ApplicationEventPublisherAware
if (bean instanceof ApplicationEventPublisherAware) {
((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
}
// MessageSourceAware
if (bean instanceof MessageSourceAware) {
((MessageSourceAware) bean).setMessageSource(this.applicationContext);
}
// ApplicationContextAware
if (bean instanceof ApplicationContextAware) {
((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
}
}

对于实现了指定 Aware 接口的 bean 类,上述方法会将相应的资源给到该 bean 实例。以 ApplicationContextAware 接口为例,实现了该接口的 bean 都持有 ApplicationContext 实例,而上述方法也正是通过调用 bean 的 setter 方法将 ApplicationContext 实例注入到 bean 实例中。

  • 自动探测 ApplicationListener 监听器

自 4.3.4 版本起,Spring 增加了对实现了 ApplicationListener 接口监听器的探测。这一机制由 ApplicationListenerDetector 类实现,核心逻辑为 `` 方法中:。ApplicationListenerDetector 实现了 MergedBeanDefinitionPostProcessor 和 DestructionAwareBeanPostProcessor 后置处理接口,并相应实现了这些后置处理器定义的模板方法,其中核心的方法 postProcessAfterInitialization 逻辑如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public Object postProcessAfterInitialization(Object bean, String beanName) {
// 仅处理实现了 ApplicationListener 接口的 bean 实例
if (bean instanceof ApplicationListener) {
// potentially not detected as a listener by getBeanNamesForType retrieval
Boolean flag = this.singletonNames.get(beanName);
// singleton 类型
if (Boolean.TRUE.equals(flag)) {
// singleton bean (top-level or inner): register on the fly
this.applicationContext.addApplicationListener((ApplicationListener<?>) bean);
}
// 非 singleton 类型
else if (Boolean.FALSE.equals(flag)) {
if (logger.isWarnEnabled() && !this.applicationContext.containsBean(beanName)) {
// inner bean with other scope - can't reliably process events
logger.warn("Inner bean '" + beanName + "' implements ApplicationListener interface " +
"but is not reachable for event multicasting by its containing ApplicationContext " +
"because it does not have singleton scope. Only top-level listener beans are allowed to be of non-singleton scope.");
}
this.singletonNames.remove(beanName);
}
}
return bean;
}

该方法针对实现了 ApplicationListener 接口的单例对象,统一注册到监听器集合中监听事件。方法中的 ApplicationListenerDetector#singletonNames 变量则是在 ApplicationListenerDetector#postProcessMergedBeanDefinition 方法中完成构建:

1
2
3
4
5
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
if (ApplicationListener.class.isAssignableFrom(beanType)) {
this.singletonNames.put(beanName, beanDefinition.isSingleton());
}
}

因此,我们可以知道该变量中记录了 beanName 与实现了 ApplicationListener 接口的 singleton 实例之间的映射关系。

应用 BeanFactoryPostProcessor 处理器

BeanFactoryPostProcessor 处理器用于对 BeanFactory 实例进行后置处理,这和 BeanPostProcessor 以 bean 实例作为处理对象有着本质的区别。所以,执行到这里就已经开始应用这些已注册的 BeanFactoryPostProcessor 处理器对前面已经准备好的 BeanFactory 对象进行处理,但是需要清楚的一点是此时还没有开始创建 bean 实例。应用 BeanFactoryPostProcessor 处理器的过程位于 AbstractApplicationContext#invokeBeanFactoryPostProcessors 方法中:

1
2
3
4
5
6
7
8
9
10
11
12
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
// 应用 BeanFactoryPostProcessor 后置处理器
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, this.getBeanFactoryPostProcessors());

// AOP 支持:LoadTimeWeaver
// Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime
// (e.g. through an @Bean method registered by ConfigurationClassPostProcessor)
if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
}

注意,这里调用 AbstractApplicationContext#getBeanFactoryPostProcessors 方法获取的 BeanFactoryPostProcessor 全部是通过编码注册而非配置的。通过调用如下方法可以以编码的方式注册 BeanFactoryPostProcessor 处理器:

1
2
3
4
public void addBeanFactoryPostProcessor(BeanFactoryPostProcessor postProcessor) {
Assert.notNull(postProcessor, "BeanFactoryPostProcessor must not be null");
this.beanFactoryPostProcessors.add(postProcessor);
}

笔者最开始看这段代码时,潜意识认为所有的 BeanFactoryPostProcessor 都是记录在 AbstractApplicationContext#beanFactoryPostProcessors 属性中的,如果以配置的方式使用过 BeanFactoryPostProcessor 的同学都知道该处理器的配置仅仅需要在配置文件中配置一个 <bean /> 标签,而不需要在其它任何地方去注册或引用这个 bean 实例。如下:

1
<bean id="myBeanFactoryPostProcessor" class="org.zhenchao.processor.MyBeanFactoryPostProcessor"/>

所以,我就去代码中寻找 Spring 是如何把上述配置给添加到 AbstractApplicationContext#beanFactoryPostProcessors 属性中的,即在哪里调用了 AbstractApplicationContext#addBeanFactoryPostProcessor 方法,结果当然是一无所获,因为出发点就是错误的。由下面的实现你将会看到这里传递的仅仅是通过编码注册的 BeanFactoryPostProcessor 处理器,而基于配置注册的 BeanFactoryPostProcessor 处理器则通过其它方式获取。

相应的实现位于 PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors 方法中,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
public static void invokeBeanFactoryPostProcessors(
ConfigurableListableBeanFactory beanFactory,
List<BeanFactoryPostProcessor> beanFactoryPostProcessors) // 保存了所有通过编码注册的 BeanFactoryPostProcessor 处理器
{

Set<String> processedBeans = new HashSet<>();

// 1. 遍历处理注册的 BeanDefinitionRegistryPostProcessor 处理器,扩展自 BeanFactoryPostProcessor
if (beanFactory instanceof BeanDefinitionRegistry) {
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
// 记录注册的 BeanFactoryPostProcessor 类型处理器
List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
// 记录注册的 BeanDefinitionRegistryPostProcessor 类型处理器
List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();

/* 获取并处理通过编码注册的 BeanDefinitionRegistryPostProcessor 处理器 */

// 1.1 处理通过编码注册 BeanDefinitionRegistryPostProcessor 处理器
for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
// 执行 BeanDefinitionRegistryPostProcessor#postProcessBeanDefinitionRegistry 方法
BeanDefinitionRegistryPostProcessor registryProcessor = (BeanDefinitionRegistryPostProcessor) postProcessor;
registryProcessor.postProcessBeanDefinitionRegistry(registry);
registryProcessors.add(registryProcessor);
} else {
regularPostProcessors.add(postProcessor);
}
}

/* 获取并处理通过配置的 BeanDefinitionRegistryPostProcessor 处理器 */

// Do not initialize FactoryBeans here: We need to leave all regular beans
// uninitialized to let the bean factory post-processors apply to them!
// Separate between BeanDefinitionRegistryPostProcessors that implement PriorityOrdered, Ordered, and the rest.
List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();

// 1.2 处理实现了 PriorityOrdered 接口的 BeanDefinitionRegistryPostProcessor 处理器
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
}
// 按照优先级对处理器进行排序
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
// 执行 BeanDefinitionRegistryPostProcessor#postProcessBeanDefinitionRegistry 方法
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
currentRegistryProcessors.clear();

// 1.3 处理实现了 Ordered 接口的 BeanDefinitionRegistryPostProcessor 处理器
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
}
// 按照指定的顺序对处理器进行排序
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
// 执行 BeanDefinitionRegistryPostProcessor#postProcessBeanDefinitionRegistry 方法
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
currentRegistryProcessors.clear();

// 1.4 处理其它的 BeanDefinitionRegistryPostProcessor 处理器
boolean reiterate = true;
while (reiterate) {
reiterate = false;
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (!processedBeans.contains(ppName)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
reiterate = true;
}
}
// 对处理器进行排序
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
// 执行 BeanDefinitionRegistryPostProcessor#postProcessBeanDefinitionRegistry 方法
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
currentRegistryProcessors.clear();
}

// 执行 BeanDefinitionRegistryPostProcessor#postProcessBeanFactory 方法
invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
// 执行 BeanFactoryPostProcessor#postProcessBeanFactory 方法
invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
} else {
// 执行 BeanFactoryPostProcessor#postProcessBeanFactory 方法
invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
}

// Do not initialize FactoryBeans here: We need to leave all regular beans
// uninitialized to let the bean factory post-processors apply to them!
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);

// 2. 遍历处理注册的 BeanFactoryPostProcessor 处理器,来自配置

// 记录实现了 PriorityOrdered 接口的 BeanFactoryPostProcessor
List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
// 记录实现了 Ordered 接口的 BeanFactoryPostProcessor
List<String> orderedPostProcessorNames = new ArrayList<>();
// 记录剩余的 BeanFactoryPostProcessor
List<String> nonOrderedPostProcessorNames = new ArrayList<>();
for (String ppName : postProcessorNames) {
if (processedBeans.contains(ppName)) {
// skip - already processed in first phase above
} else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
} else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
orderedPostProcessorNames.add(ppName);
} else {
nonOrderedPostProcessorNames.add(ppName);
}
}

// 2.1 处理实现了 PriorityOrdered 接口的 BeanDefinitionRegistryPostProcessor 处理器
sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);

// 2.2 处理实现了 Ordered 接口的 BeanDefinitionRegistryPostProcessor 处理器
List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());
for (String postProcessorName : orderedPostProcessorNames) {
orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
sortPostProcessors(orderedPostProcessors, beanFactory);
invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);

// 2.3 处理剩余的 BeanDefinitionRegistryPostProcessor 处理器
List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
for (String postProcessorName : nonOrderedPostProcessorNames) {
nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);

// Clear cached merged bean definitions since the post-processors might have
// modified the original metadata, e.g. replacing placeholders in values...
beanFactory.clearMetadataCache(); // 执行一些清理工作
}

可以看到针对编码注册和以配置方式注册的 BeanFactoryPostProcessor 处理器实例,Spring 的获取方式是不一样的。前者都是注册到之前提到的 AbstractApplicationContext#beanFactoryPostProcessors 属性中,而后者都是通过 BeanFactory#getBean 方法获取到,所以是由 IoC 容器管理的。

上述方法的执行流程可以分为处理 BeanDefinitionRegistryPostProcessor 和处理 BeanFactoryPostProcessor 两部分。BeanDefinitionRegistryPostProcessor 扩展自 BeanFactoryPostProcessor,继承关系如下:

1
2
3
4
5
6
7
public interface BeanFactoryPostProcessor {
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
}

public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {
void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;
}

整个方法的前半部分都是在应用 BeanDefinitionRegistryPostProcessor#postProcessBeanDefinitionRegistry 方法对实现了 BeanDefinitionRegistry 接口的 BeanFactory 实例进行后置处理,而后半部分则是在应用 BeanFactoryPostProcessor#postProcessBeanFactory 方法对所有类型的 BeanFactory 实例进行后置处理。考虑配置 BeanFactoryPostProcessor 顺序的不确定性,Spring 支持对其设置优先级。由实现也可以看出,Spring 会依次应用 PriorityOrdered、Ordered,以及剩余类型的处理器,并针对各类型按照比较器进行排序处理。

注册 BeanPostProcessor 处理器

不同于上一步介绍的对 BeanFactoryPostProcessor 的处理过程,对于 BeanPostProcessor 而言,这一步仅仅是注册而非应用。因为 BeanPostProcessor 处理器作用于 bean 实例之上,而当前还没有开始创建 bean 实例。之前讲解 BeanFactory#getBean 过程的文章中我们已经分析过,对于 BeanPostProcessor 的应用是发生在 bean 实例的创建和初始化过程中,具体来说是围绕 bean 初始化过程的前后:

1
2
3
4
5
6
7
8
9
10
11
public interface BeanPostProcessor {

default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}

default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}

}

注册 BeanPostProcessor 处理器的过程本质上是将配置的 BeanPostProcessor 实例记录到 AbstractBeanFactory#beanPostProcessors 属性中的过程。在简单容器中需要通过调用 AbstractBeanFactory#addBeanPostProcessor 方法手动注册我们实现的 BeanPostProcessor 处理器,而在高级容器中则支持自动扫描注册。相应的实现位于 AbstractApplicationContext#registerBeanPostProcessors 方法中,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this);
}

// org.springframework.context.support.PostProcessorRegistrationDelegate#registerBeanPostProcessors
public static void registerBeanPostProcessors(
ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {

// 获取已加载 BeanPostProcessor 类型的 beanName 集合
String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);

// Register BeanPostProcessorChecker that logs an info message when
// a bean is created during BeanPostProcessor instantiation, i.e. when
// a bean is not eligible for getting processed by all BeanPostProcessors.
int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
// 注册一个 BeanPostProcessorChecker,用于在还没有注册后置处理器就开始实例化 bean 的情况下打印日志
beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));

// 记录实现了 PriorityOrdered 接口的 BeanPostProcessor 处理器
List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
// 存放 MergedBeanDefinitionPostProcessor 处理器
List<BeanPostProcessor> internalPostProcessors = new ArrayList<>();
// 记录实现了 Ordered 接口的 BeanPostProcessor 处理器
List<String> orderedPostProcessorNames = new ArrayList<>();
// 记录其它的 BeanPostProcessor 处理器
List<String> nonOrderedPostProcessorNames = new ArrayList<>();
// 遍历对加载到 BeanPostProcessor 进行分类
for (String ppName : postProcessorNames) {
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
priorityOrderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
} else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
orderedPostProcessorNames.add(ppName);
} else {
nonOrderedPostProcessorNames.add(ppName);
}
}

// 1. 注册实现了 PriorityOrdered 接口的 BeanPostProcessor 处理器,不包含 MergedBeanDefinitionPostProcessor
sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);

// 2. 注册实现了 Ordered 接口的 BeanPostProcessor 处理器
List<BeanPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());
for (String ppName : orderedPostProcessorNames) {
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
orderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
sortPostProcessors(orderedPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, orderedPostProcessors);

// 3. 注册其余除 MergedBeanDefinitionPostProcessor 类型以外的 BeanPostProcessor 处理器
List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
for (String ppName : nonOrderedPostProcessorNames) {
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
nonOrderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);

// 4. 注册所有的 MergedBeanDefinitionPostProcessor 处理器
sortPostProcessors(internalPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, internalPostProcessors);

// Re-register post-processor for detecting inner beans as ApplicationListeners,
// moving it to the end of the processor chain (for picking up proxies etc).
// 重新注册 ApplicationListenerDetector 探测器,将其移到链尾
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
}

上述实现与处理 BeanFactoryPostProcessor 处理的过程大同小异,同样按优先级进行注册。

初始化国际化资源

笔者之前所负责的几个项目都需要考虑国际化支持,有的直接基于 JDK 原生的 ResourceBundle,有的则基于 Spring 提供的 MessageSource。在具体分析 MessageSource 的初始化过程之前,我们先来了解一下 Spring 国际化支持的设计与简单使用。

Spring MessageSource 支持本质上也是对 ResourceBundle 的封装。MessageSource 接口的定义如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public interface MessageSource {

/**
* 获取指定语言的文案信息,参数说明:
* - code: 属性名称
* - args: 用于传递格式化参数
* - defaultMessage: 表示在找不到指定属性时返回的默认信息
* - locale 表示本地化对象
*/
String getMessage(String code, Object[] args, String defaultMessage, Locale locale);

/**
* 获取指定语言的文案信息,当找不到对应属性时直接抛出异常
*/
String getMessage(String code, Object[] args, Locale locale) throws NoSuchMessageException;

/**
* 获取指定语言的文案信息,采用 MessageSourceResolvable 来封装第一个方法中的前三个参数
*/
String getMessage(MessageSourceResolvable resolvable, Locale locale) throws NoSuchMessageException;

}

Spring MessageSource 相关类的继承关系如下图所示:

image

其中 HierarchicalMessageSource 的设计为 MessageSource 提供了层次支持,建立了父子层级结构。ResourceBundleMessageSource 和 ReloadableResourceBundleMessageSource 是我们常用的两个类,均可以看做是对 JDK 原生国际化支持的封装,后者相对于前者提供了定时更新资源文件的支持,避免资源更新时重启系统。StaticMessageSource 用于支持编码式资源注册,DelegatingMessageSource 则可以看作是 MessageSource 的一个代理,必要时对 MessageSource 进行封装。

下面通过示例演示一下 MessageSource 的简单使用。首先我们定义好国际化资源文件:

  • resource.properties
1
spring=Spring framework is a good design, the latest version is {0}
  • resource_zh.properties
1
spring=Spring 框架設計精良,當前最新版本是 {0}
  • resource_zh_CN.properties
1
spring=Spring 框架设计精良,当前最新版本是 {0}

需要注意的是,如果资源文件包含非 ASCII 字符,则需要将文本内容转换成 Unicode 编码,JDK 自带的 native2ascii 工具可以达到目的,操作如下:

1
native2ascii -encoding utf-8 resource_zh.properties resource_zh_tmp.properties

然后我们在配置文件中进行如下配置:

1
2
3
4
5
6
7
8
<!--推荐以 messageResource 作为 id-->
<bean id="messageResource" class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basenames">
<list>
<value>i18n/resource</value>
</list>
</property>
</bean>

调用方式如下:

1
2
3
4
5
ApplicationContext context = new ClassPathXmlApplicationContext("spring-core.xml");
Object[] params = {"5.2.6.RELEASE"};
System.out.println(context.getMessage("spring", params, Locale.ENGLISH));
System.out.println(context.getMessage("spring", params, Locale.TRADITIONAL_CHINESE));
System.out.println(context.getMessage("spring", params, Locale.SIMPLIFIED_CHINESE));

因为 ApplicationContext 同样实现了 MessageSource 接口,所以可以直接调用 ApplicationContext#getMessage 方法,但是这样调用的前提是配置中的 ID 必须设置为 messageResource。上述示例如下:

1
2
3
Spring framework is a good design, the latest version is 5.2.6.RELEASE
Spring 框架設計精良,當前最新版本是 5.2.6.RELEASE
Spring 框架设计精良,当前最新版本是 5.2.6.RELEASE

下面分析高级容器对于 MessageSource 的初始化过程,由 AbstractApplicationContext#initMessageSource 方法实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
protected void initMessageSource() {
ConfigurableListableBeanFactory beanFactory = this.getBeanFactory();
// 存在 ID 为 messageSource 的 bean 实例
if (beanFactory.containsLocalBean(MESSAGE_SOURCE_BEAN_NAME)) {
// 获取 MessageSource 实例
this.messageSource = beanFactory.getBean(MESSAGE_SOURCE_BEAN_NAME, MessageSource.class);
// Make MessageSource aware of parent MessageSource.
if (this.parent != null && this.messageSource instanceof HierarchicalMessageSource) {
HierarchicalMessageSource hms = (HierarchicalMessageSource) this.messageSource;
if (hms.getParentMessageSource() == null) {
// Only set parent context as parent MessageSource if no parent MessageSource registered already.
hms.setParentMessageSource(this.getInternalParentMessageSource());
}
}
}
// 不存在 ID 为 messageSource 的 bean 实例
else {
// 创建一个 DelegatingMessageSource 代理对象
DelegatingMessageSource dms = new DelegatingMessageSource();
// 尝试继承父上下文中的 MessageSource 实例
dms.setParentMessageSource(this.getInternalParentMessageSource());
this.messageSource = dms;
// 以 messageSource 作为 ID 注册代理的 DelegatingMessageSource 对象
beanFactory.registerSingleton(MESSAGE_SOURCE_BEAN_NAME, this.messageSource);
}
}

前面的示例在配置时推荐将 ID 配置为 messageSource 是有原因的,通过阅读上述实现一目了然。代码中硬编码要求我们配置 messageSource 作为 MessageSource 实例的 ID,否则不执行初始化,而是创建一个默认的代理,(如果存在的话)委托给父上下文中的 MessageSource 实例。如果通过调用 ApplicationContext#getMessage 方法尝试获取对应的资源则会出现异常,此时就需要我们手动指定 ApplicationContext#getBean 时的名称。然而,Spring 并不推荐这样做,既然框架以约定的方式提供了相应的实现,还是推荐以 messageSource 作为 ID 进行配置为好,毕竟约定优于配置。

注册事件通知广播器

事件广播和监听机制是典型的观察者模式实现,而 ApplicationEventMulticaster 则充当观察者模式中主题角色。如果在 Spring 中希望监听事件广播器广播的事件,需要定义一个实现了 ApplicationListener 接口的监听器。Spring 支持通过编码注册和自动扫描注册两种方式注册 ApplicationListener 监听器,这个我们稍后会细说,首先来看一下广播器的初始化过程,实现位于 AbstractApplicationContext#initApplicationEventMulticaster 方法中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
protected void initApplicationEventMulticaster() {
ConfigurableListableBeanFactory beanFactory = this.getBeanFactory();
// 包含 ID 为 applicationEventMulticaster 的 bean 实例
if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
this.applicationEventMulticaster =
beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
}
// 不包含 ID 为 applicationEventMulticaster 的 bean 实例
else {
// 创建并注册一个 SimpleApplicationEventMulticaster 实例
this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
}
}

如果我们以约定的方式配置了自定义的事件广播器,则上述过程会初始化该广播器实例;否则容器会创建并注册一个默认的 SimpleApplicationEventMulticaster 广播器。下面以 SimpleApplicationEventMulticaster 广播器为例分析广播事件通知的过程,主要来看对于 ApplicationEventMulticaster#multicastEvent 方法的实现,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : this.resolveDefaultEventType(event));
Executor executor = this.getTaskExecutor();
// 获取并回调监听指定事件的各个监听器
for (ApplicationListener<?> listener : this.getApplicationListeners(event, type)) {
if (executor != null) {
// 异步执行
executor.execute(() -> this.invokeListener(listener, event));
} else {

this.invokeListener(listener, event);
}
}
}

protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
ErrorHandler errorHandler = this.getErrorHandler();
if (errorHandler != null) {
try {
this.doInvokeListener(listener, event);
} catch (Throwable err) {
errorHandler.handleError(err);
}
} else {
this.doInvokeListener(listener, event);
}
}

private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
try {
// 回调 ApplicationListener#onApplicationEvent 方法
listener.onApplicationEvent(event);
} catch (ClassCastException ex) {
String msg = ex.getMessage();
if (msg == null || this.matchesClassCastMessage(msg, event.getClass())) {
// Possibly a lambda-defined listener which we could not resolve the generic event type for
// -> let's suppress the exception and just log a debug message.
Log logger = LogFactory.getLog(this.getClass());
if (logger.isTraceEnabled()) {
logger.trace("Non-matching event type for listener: " + listener, ex);
}
} else {
throw ex;
}
}
}

典型的回调观察者监听方法的逻辑,如果对于观察者模式了解的话,这里的逻辑会比较好理解。

注册事件监听器

既然有被观察者,就应该有对应的观察者,事件监听器 ApplicationListener 充当观察者角色。我们需要通过注册 ApplicationListener 来监听事件通知,针对 ApplicationListener 的注册,可以通过编码的方式进行注册,如果我们将其配置到配置文件中,容器也会自动扫描并注册。注册 ApplicationListener 的过程由 AbstractApplicationContext#registerListeners 方法实现,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
protected void registerListeners() {
// 1. 注册所有通过编码方式添加的事件监听器
for (ApplicationListener<?> listener : this.getApplicationListeners()) {
this.getApplicationEventMulticaster().addApplicationListener(listener);
}

// 2. 扫描注册以配置方式添加的事件监听器
String[] listenerBeanNames = this.getBeanNamesForType(ApplicationListener.class, true, false);
for (String listenerBeanName : listenerBeanNames) {
this.getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
}

// 3. 发布需要提前广播的事件
Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
this.earlyApplicationEvents = null;
if (earlyEventsToProcess != null) {
// 调用广播器的 ApplicationEventMulticaster#multicastEvent 方法
for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
this.getApplicationEventMulticaster().multicastEvent(earlyEvent);
}
}
}

上一步已经完成了对于事件广播器 ApplicationEventMulticaster 的注册操作,这一步所完成的工作就是将编码和配置注册的 ApplicationListener 注册到广播器中。如果在前面的过程中已经记录了一些需要广播的事件,那么在这一步会触发对于这些事件的广播通知,因为此时已经有事件广播器可用了。

实例化非延迟加载的 singleton 类对象

记得最开始学习 Spring 框架的时候,就看到说 BeanFactory 和 ApplicationContext 有一个很大的区别,即 BeanFactory 在初始化容器时不会实例化 bean 对象,而 ApplicationContext 则会实例化所有非延迟加载的 singleton 类实例。这是因为 ApplicationContext 会在初始化容器时通过调用 AbstractApplicationContext#finishBeanFactoryInitialization 方法对所有非延迟加载的 singleton 类进行实例化操作,实现如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
// 如果存在类型转换器,则进行加载
if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME)
&& beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
beanFactory.setConversionService(beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
}

// 如果不存在 embedded value resolver 则设置一个默认的
if (!beanFactory.hasEmbeddedValueResolver()) {
beanFactory.addEmbeddedValueResolver(new StringValueResolver() {
@Override
public String resolveStringValue(String strVal) {
return getEnvironment().resolvePlaceholders(strVal);
}
});
}

// AOP支持,实例化 LoadTimeWeaverAware
String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
for (String weaverAwareName : weaverAwareNames) {
this.getBean(weaverAwareName);
}

beanFactory.setTempClassLoader(null);

// 冻结所有 bean 的定义,不再允许更改
beanFactory.freezeConfiguration();

// 实例化所有的非延迟加载的bean(非abstract && 单例 && 非延迟加载)
beanFactory.preInstantiateSingletons();
}

由上述实现可以知道,Spring 在实例化非延迟加载的 singleton 对象之前先校验一些必要的工具实例是否存在,如果没有注册则会创建一个默认的作为代替。然后会冻结所有的 BeanDefinition 定义,毕竟即将开始执行实例化了,后续的更改也不会再生效。完成准备工作之后,容器即开始实例化所有满足条件(非 abstract && 单例 && 非 lazy-init)的 bean 对象。

实例化的过程由 DefaultListableBeanFactory#preInstantiateSingletons 方法实现,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
public void preInstantiateSingletons() throws BeansException {
// Iterate over a copy to allow for init methods which in turn register new bean definitions.
// While this may not be part of the regular factory bootstrap, it does otherwise work fine.
List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

// 遍历实例化所有满足条件的 bean 对象
for (String beanName : beanNames) {
// 获取对应 bean 最终的 BeanDefinition 定义
RootBeanDefinition bd = this.getMergedLocalBeanDefinition(beanName);
// 不是 abstract && 单例 && 不是 lazy-init
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
// 处理 FactoryBean
if (this.isFactoryBean(beanName)) {
// 获取 FactoryBean 对象
Object bean = this.getBean(FACTORY_BEAN_PREFIX + beanName);
if (bean instanceof FactoryBean) {
final FactoryBean<?> factory = (FactoryBean<?>) bean;
boolean isEagerInit;
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>) ((SmartFactoryBean<?>) factory)::isEagerInit,
this.getAccessControlContext());
} else {
isEagerInit = (factory instanceof SmartFactoryBean && ((SmartFactoryBean<?>) factory).isEagerInit());
}
if (isEagerInit) {
this.getBean(beanName);
}
}
}
// 加载普通 bean 对象
else {
this.getBean(beanName);
}
}
}

/* 完成对所有满足条件的 singleton bean 的实例化操作 */

// 遍历处理所有实现了 SmartInitializingSingleton 接口的 bean 实例
for (String beanName : beanNames) {
Object singletonInstance = this.getSingleton(beanName);
// 回调 SmartInitializingSingleton#afterSingletonsInstantiated 方法
if (singletonInstance instanceof SmartInitializingSingleton) {
final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
smartSingleton.afterSingletonsInstantiated();
return null;
}, this.getAccessControlContext());
} else {
smartSingleton.afterSingletonsInstantiated();
}
}
}
}

Spring 在 4.1 版本增加了 SmartInitializingSingleton 接口,实现了该接口的单例可以感知所有单例实例化完成的事件,而回调接口中声明的 SmartInitializingSingleton#afterSingletonsInstantiated 方法的逻辑由上述方法完成。

完成刷新过程

经过前面的过程,对于 ApplicationContext 而言已经完成了加载并解析配置,以及实例化所有非延迟加载的 singleton 类对象的过程。也就是说,高级容器初始化过程的主要工作已经做完了,最后需要调用 AbstractApplicationContext#finishRefresh 方法完成整个初始化进程,实现如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
protected void finishRefresh() {
// 初始化 LifecycleProcessor
this.initLifecycleProcessor();

// 调用所有实现了 Lifecycle 的 start 方法
this.getLifecycleProcessor().onRefresh();

// 发布上下文刷新完毕事件
this.publishEvent(new ContextRefreshedEvent(this));

// 注册到 LiveBeansView MBean
LiveBeansView.registerApplicationContext(this);
}

Spring 很早就提供了 Lifecycle 接口,实现了该接口的 bean 可以感知到容器的启动和关闭状态,对应接口的 Lifecycle#startLifecycle#stop 方法,而方法 Lifecycle#start 的回调则位于此。Lifecycle 中方法的执行需要依赖于 LifecycleProcessor 处理器,我们可以自定义 LifecycleProcessor 实现,否则容器会创建一个默认的 DefaultLifecycleProcessor 对象,然后基于定义的 LifecycleProcessor 处理器调用满足条件的 bean 实例的 Lifecycle#start 方法。在完成了这一操作后,容器的初始化过程也就完成了,此时容器可以将容器刷新完毕事件通知到对应的事件监听器,即所有订阅 ContextRefreshedEvent 事件的监听器。

总结

至此,高级容器的初始化过程我们已经分析完了,不同于 BeanFactory 在该阶段仅仅是将静态配置转换成容器中对应的 BeanDefinition 实例,ApplicationContext 因为需要实例化所有非延迟加载的 singleton 对象,所以大部分的 bean 对象已经以实例的形式注册到容器中,后续我们再调用 ApplicationContext#getBean 方法也仅需要针对非单例的 bean 对象才执行复杂的实例化操作,所以在高级容器中本篇所分析的过程基本可以概括容器的大部分工作。

参考

  1. Spring 源码深度解析