封面画师:T5-茨舞(微博)     封面ID:108988374

本文涉及的代码:springboot-study/extension-point-summary

参考链接:Springboot扩展点

本文基于 SpringBoot 3.1.x 和 JDK17

0. 前言

Spring 的核心是容器,SpringBoot 则是对 Spring 的又一层封装,一个注解、一个方法将复杂功能全部隐藏,实现开箱即用,但如果需要对某些功能进行定制,就需要利用 SpringBoot 预留的拓展点来实现。

学习 SpringBoot 的简单使用并不难,学习 SpringBoot 如何将复杂功能进行简化、预留的拓展点如何使用才是重中之重。

1. 应用上下文初始化器

1.1 拓展点的作用

应用上下文初始化器,即:ApplicationContextInitializer,它并非由 SpringBoot 提供,而是在 Spring 中就存在的:

1
2
3
4
@FunctionalInterface
public interface ApplicationContextInitializer<C extends ConfigurableApplicationContext> {
void initialize(C applicationContext);
}

在 Spring 容器初始化时,所有实现 ApplicationContextInitializer 接口的类都会被实例化;在 Spring 容器 refresh 前,ApplicationContextInitializer 所有实现类的 initialize() 方法都会被依次调用,调用顺序可使用 Spring 提供的 Ordered 接口、@Order 接口等方式进行指定。

ApplicationContextInitializer 接口常用于需要对应用上下文进行初始化的的 Web 应用程序中,比如在上下文环境中注册运行环境属性或激活配置文件。

1.2 使用方式

实现 ApplicationContextInitializer 接口,重写 initialize() 方法。

由于 initialize() 方法的执行时间点在 Spring 容器未初始化完成前,因此将实现类交由 Spring 管理,并以此来执行重写的 initialize() 方法是行不通的,此时可以使用 SpringBoot 的自动装配机制、读取配置文件信息或手动添加初始化器来添加初始化器。

编写 ApplicationContextInitializer 的三个实现类,在实现类中增加系统变量:

1
2
3
1=ONE
2=TWO
3=THREE

比如:

1
2
3
4
5
6
static class FirstApplicationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
@Override
public void initialize(ConfigurableApplicationContext context) {
putProperty(context, "1", "ONE");
}
}

利用 SpringBoot 的自动装配机制

创建 META-INF/spring.factories 文件,在该文件中添加 ApplicationContextInitializer 的实现类信息:

1
2
org.springframework.context.ApplicationContextInitializer = \
indi.mofan.summary.a01.A01ExtensionPoint.FirstApplicationContextInitializer

读取配置文件信息

创建 application.properties 配置文件,在配置文件中以 context.initializer.classes 为 Key,添加 ApplicationContextInitializer 的实现类信息:

1
context.initializer.classes=indi.mofan.summary.a01.A01ExtensionPoint.SecondApplicationContextInitializer

手动添加初始化器

创建 SpringApplication 对象,调用其 addInitializers() 方法手动添加初始化器。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/**
* @author mofan
* @date 2023/5/21 16:58
*/
@SpringBootApplication
public class A01ExtensionPoint {
public static void main(String[] args) {
SpringApplication application = new SpringApplication(A01ExtensionPoint.class);
application.addInitializers(new ThirdApplicationContextInitializer());
ConfigurableApplicationContext context = application.run(args);
ConfigurableEnvironment environment = context.getEnvironment();
System.out.println(environment.getProperty("1")); // ONE
System.out.println(environment.getProperty("2")); // TWO
System.out.println(environment.getProperty("3")); // THREE
context.close();
}
}

1.3 实例化与执行

实例化

在 SpringBoot 中,构造 SpringApplication 对象时会调用 setInitializers() 方法添加所有 ApplicationContextInitializer 实例。见:

1
2
3
4
5
6
7
8
9
10
11
12
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
this.webApplicationType = WebApplicationType.deduceFromClasspath();
this.bootstrapRegistryInitializers = new ArrayList<>(
getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
// 实例化时机
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();
}

执行

调用 SpringApplication 对象的 run() 方法时,在执行 refreshContext() 方法前调用 prepareContext() 方法,在该方法中调用 applyInitializers() 方法执行上一步添加的所有 ApplicationContextInitializer 实例的 initialize() 方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// org.springframework.boot.SpringApplication#prepareContext()
private void prepareContext(DefaultBootstrapContext bootstrapContext,
ConfigurableApplicationContext context,
ConfigurableEnvironment environment,
SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments,
Banner printedBanner) {
context.setEnvironment(environment);
postProcessApplicationContext(context);
addAotGeneratedInitializerIfNecessary(this.initializers);
// 执行时机
applyInitializers(context);
listeners.contextPrepared(context);

// --snip--
}

1.4 内置实现

DelegatingApplicationContextInitializer

实例化 ApplicationContextInitializer 时,是通过 SpringFactoriesLoader.loadFactoryNames() 方法获取 META-INF/spring.factories 文件中的实现类信息,而配置文件中的实现类信息是通过 DelegatingApplicationContextInitializer 得到的。

该实现类信息被 SpringBoot 默认添加到 META-INF/spring.factories 文件中,因此能够直接获取到其实例。

而后在执行 DelegatingApplicationContextInitializerinitialize() 方法时,获取配置文件中的 ApplicationContextInitializer 实现类信息,构造它们的实例并执行 initialize() 方法。

ContextIdApplicationContextInitializer

该实现类用于设置应用上下文 ID,如果配置文件中未显示指定 spring.application.name 的值,那么默认的应用上下文 ID 为 application

其他内置实现

  • ConfigurationWarningsApplicationContextInitializer:添加后置处理器 ConfigurationWarningsPostProcessor 到 Spring 容器中,用于打印添加 Bean 时产生的警告信息;

  • ServerPortInfoApplicationContextInitializer:该实现类也实现了 ApplicationListener 接口,其 initialize() 方法就是将自身添加到 Spring 容器中,用于监听 WebServerInitializedEvent

  • 还有一些其他内置实现,其功能要么是添加后置处理器、要么是添加监听器,作用都大差不差。

2. Bean 工厂后置处理器

2.1 拓展点的作用

Bean 工厂后置处理器,即:BeanFactoryPostProcessor,它也并非 SpringBoot 提供,而是在 Spring 中就存在的:

1
2
3
4
@FunctionalInterface
public interface BeanFactoryPostProcessor {
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
}

在 Spring 生命周期内,BeanFactoryPostProcessor 实例的 postProcessBeanFactory() 方法 只会 执行一次;在容器读取到所有的 BeanDefinition 后,但 Bean 尚未初始化前,读取 BeanDefinition 信息,对其中的属性进行修改或添加。

BeanFactoryPostProcessor 接口常用于修改应用程序上下文中系统管理员的自定义配置文件绑定的 Bean 属性信息,比如在读取配置文件中加密的敏感信息时,对这些信息进行解密。

2.2 使用方式

实现 BeanFactoryPostProcessor 接口,重写 postProcessBeanFactory() 方法,并 将实现类交由 Spring 管理。

postProcessBeanFactory() 方法的执行时机实在 Spring 容器读取到所有 BeanDefinition 后,因此将实现类交由 Spring 管理即可在对应时机执行 postProcessBeanFactory() 方法。

比如容器中已经存在名为 dog 的 Bean:

1
2
3
4
5
6
7
@Getter
@Setter
@Component("dog")
static class Dog {
private String name = "旺财";
private Integer age = 2;
}

现在需要修改该 Bean 的 name 信息,就需要使用到 BeanFactoryPostProcessor 接口:

1
2
3
4
5
6
7
8
9
@Component
static class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
ScannedGenericBeanDefinition definition = (ScannedGenericBeanDefinition) beanFactory.getBeanDefinition("dog");
MutablePropertyValues properties = definition.getPropertyValues();
properties.add("name", "小黑");
}
}
1
2
3
4
5
6
7
8
9
10
@SpringBootApplication
public class A02ExtensionPoint {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(A02ExtensionPoint.class, args);
Dog dog = context.getBean(Dog.class);
System.out.println(dog.getName());
System.out.println(dog.getAge());
context.close();
}
}
小黑
2

2.3 执行入口

还是从调用 SpringApplication 对象的 run() 方法入手:

1
2
3
4
5
6
7
8
9
10
11
12
13
public ConfigurableApplicationContext run(String... args) {
// --snip--
try {
// --snip--
prepareContext(bootstrapContext, context, environment,
listeners, applicationArguments, printedBanner);
// 在这个方法里执行
refreshContext(context);
afterRefresh(context, applicationArguments);
// --snip--
}
// --snip--
}
1
2
3
4
5
6
7
private void refreshContext(ConfigurableApplicationContext context) {
if (this.registerShutdownHook) {
shutdownHook.registerApplicationContext(context);
}
// 继续调用 refresh() 方法
refresh(context);
}
1
2
3
4
protected void refresh(ConfigurableApplicationContext applicationContext) {   
// 调用 applicationContext 的 refresh() 方法
applicationContext.refresh();
}

ConfigurableApplicationContext 有三种实现类,但直接的实现类只有 AbstractApplicationContext 一种,另外两种实现类又会继承 AbstractApplicationContext,因此重点分析 AbstractApplicationContext#refresh() 方法。

AbstractApplicationContext#refresh() 方法很重要,后续还会讲到。

refresh() 方法中调用了 invokeBeanFactoryPostProcessors() 方法,也是在这个方法中完成对所有 BeanFactoryPostProcessor 实例的 postProcessBeanFactory() 方法的调用。

invokeBeanFactoryPostProcessors() 方法只是一个入口,真正的实现是:

1
org.springframework.context.support.PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors(org.springframework.beans.factory.config.ConfigurableListableBeanFactory, java.util.List<org.springframework.beans.factory.config.BeanFactoryPostProcessor>)

这个方法除了接收 ConfigurableListableBeanFactory 对象外,还接收了 BeanFactoryPostProcessor 实例列表。

2.4 第二个参数的来源

BeanFactoryPostProcessor 实例列表是从哪来的呢?

BeanFactoryPostProcessor 实例不应该直接从 BeanFactory 中获取吗?这里传入的又是什么呢?

传入的 BeanFactoryPostProcessor 实例列表是 AbstractApplicationContext 中的一个成员变量 beanFactoryPostProcessors

1
private final List<BeanFactoryPostProcessor> beanFactoryPostProcessors = new ArrayList<>();

提供了通过 addBeanFactoryPostProcessor() 方法作为修改的方式:

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

调用该方法的地方共有两处:

  • org.springframework.boot.SpringApplication#prepareContext()
  • org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer#initialize()

前者会在 SpringApplication#run() 方法中、在 refreshContext() 方法调用前被调用,因此在执行 refresh() 方法时能够拿到添加的 BeanFactoryPostProcessor 实例;后者的 ConfigurationWarningsApplicationContextInitializer 是先前介绍的 ApplicationContextInitializer 的一个实现类,其 initialize() 方法会在 prepareContext() 方法中被调用,也能够在后续执行时拿到被添加的 BeanFactoryPostProcessor 实例。

2.5 执行的逻辑

又回到 PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors() 方法,源码里先是一大段注释,简单来说就是 不要瞎重构这个方法来减少多个循环和多个列表的使用,因为那是故意为之的,具体来说是不能通过调用 getBean() 方法获取某些 BeanFactoryPostProcessor,这会到导致 BeanFactoryPostProcessor 提前被实例化,或者以错误的顺序在 ApplicationContext 中注册 BeanFactoryPostProcessor,最后甚至还给出了“耻辱墙”,里面过滤出所有被拒绝的相关 PR。😂

源码中充满了注释,像极了工作中写满注释不让同事乱动的样子。🤣

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
145
public static void invokeBeanFactoryPostProcessors(
ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {

// 首先执行 BeanDefinitionRegistryPostProcessors,如果有。
// processedBeans 里存储了已经处理过的 Bean 的 name
Set<String> processedBeans = new HashSet<>();

// 判断 beanFactory 是否是 BeanDefinitionRegistry,
// 通常是 DefaultListableBeanFactory,因此满足条件
if (beanFactory instanceof BeanDefinitionRegistry registry) {
List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
// BeanDefinitionRegistryPostProcessor 是 BeanFactoryPostProcessor 的子类
List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();

// 对直接传入的 BeanFactoryPostProcessor 进行分类并执行
for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
if (postProcessor instanceof BeanDefinitionRegistryPostProcessor registryProcessor) {
// 直接执行 BeanDefinitionRegistryPostProcessor
registryProcessor.postProcessBeanDefinitionRegistry(registry);
registryProcessors.add(registryProcessor);
}
else {
regularPostProcessors.add(postProcessor);
}
}

// 不初始化 FactoryBeans,需要保证所有常规 Bean 未被初始化,以便让
// BeanFactoryPostProcessor 处理他们。将 BeanDefinitionRegistryPostProcessors
// 分成三类,分别是实现了 PriorityOrdered、实现了 Ordered 和其他的。
// 这里分类的是 BeanFactory 中的 BeanDefinitionRegistryPostProcessor
List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();

// 首先执行实现了 PriorityOrdered 的 BeanDefinitionRegistryPostProcessors
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);
// 放到存放 BeanDefinitionRegistryPostProcessor 的总集合里
// 里面不仅有 BeanFactory 中的,还有直接传入的
registryProcessors.addAll(currentRegistryProcessors);
// 执行
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());
// 清空下,方便后续使用
currentRegistryProcessors.clear();

// 接下来执行实现了 Ordered 的 BeanDefinitionRegistryPostProcessors
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);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());
currentRegistryProcessors.clear();

// 前面在执行 BeanDefinitionRegistryPostProcessors、或者后续执行其他的
// BeanDefinitionRegistryPostProcessors 时,可能会一些添加
// BeanDefinitionRegistryPostProcessors 的 BeanDefinition,因此要不断执行
// BeanDefinitionRegistryPostProcessors,直到不再出现其他处理器为止
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);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());
currentRegistryProcessors.clear();
}

// 前面已经把 BeanDefinitionRegistryPostProcessors 执行了
// 接下来执行每个 BeanFactoryPostProcessor,也是先执行 BeanDefinitionRegistryPostProcessors
invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
}

else {
// 调用在上下文实例中注册的 BeanFactoryPostProcessor,也就是直接传进来的
invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
}


// 这里也不初始化 FactoryBeans,要保证所有的常规 Bean 未被初始化,以便让 BeanFactoryPostProcessor 处理他们
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);

// 接下来同样是分类,将 BeanFactoryPostProcessors 分成三类,分别是实现了 PriorityOrdered、
// 实现了 Ordered 和其他的。
List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
List<String> orderedPostProcessorNames = new ArrayList<>();
List<String> nonOrderedPostProcessorNames = new ArrayList<>();
for (String ppName : postProcessorNames) {
if (processedBeans.contains(ppName)) {
// 在前面处理过的,直接跳过
}
else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
}
else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
// 这里没有直接通过 getBean() 获取,因为 getBean() 会导致 Bean 提前初始化
orderedPostProcessorNames.add(ppName);
}
else {
nonOrderedPostProcessorNames.add(ppName);
}
}

// 首先执行实现了 PriorityOrdered 的 BeanFactoryPostProcessors
sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);

// 接下来执行实现了 Ordered 的 BeanFactoryPostProcessors
List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());
for (String postProcessorName : orderedPostProcessorNames) {
orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
sortPostProcessors(orderedPostProcessors, beanFactory);
invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);

// 最后执行其他的 BeanFactoryPostProcessors
List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
for (String postProcessorName : nonOrderedPostProcessorNames) {
nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);

// 清除合并的 BeanDefinition,因为后置处理器中可能已经修改了原始元数据,
// 比如替换 value 中的占位符
beanFactory.clearMetadataCache();
}

PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors() 方法不仅处理了 BeanFactoryPostProcessor,还处理了 BeanDefinitionRegistryPostProcessor,后者被称为“Bean 定义注册器后置处理器”,是一种容器级的后置处理器,那它又是什么呢?

3. Bean 定义注册器后置处理器

3.1 拓展点的作用

Bean 定义注册器后置处理器,即:BeanDefinitionRegistryPostProcessor,它同样并非 SpringBoot 提供,也是在 Spring 中就存在的:

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

它是容器级别的后置处理器,将在 Spring 容器初始化后、refresh 前(即 Bean 被抽象成 BeanDefinition 后、未实例化前)执行。

提供了 postProcessBeanDefinitionRegistry() 方法,使用 BeanDefinitionRegistry 能够对 BeanDefinition 进行增删改查。

该接口继承了 BeanFactoryPostProcessor 接口,是它的一个拓展,通过前文的介绍可知它们都是在同一个方法中被执行的,只不过 BeanDefinitionRegistryPostProcessorBeanFactoryPostProcessor 更先 执行,因此 可以使用 BeanDefinitionRegistryPostProcessor 可以用来注册 BeanFactoryPostProcessor 的 BeanDefinition

3.2 使用方式

实现 BeanDefinitionRegistryPostProcessor 接口,重写 postProcessBeanDefinitionRegistry() 方法,并 将实现类交由 Spring 管理。

比如存在 Cat 类,它并未交由 Spring 管理:

1
2
3
4
5
6
@Getter
@Setter
static class Cat {
private String name;
private String age;
}

编写实现类,实现 BeanDefinitionRegistryPostProcessor 接口,尝试注册 Cat 类型的 BeanDefinition:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@Component
static class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {
RootBeanDefinition beanDefinition = new RootBeanDefinition();
beanDefinition.setBeanClass(Cat.class);
PropertyValue name = new PropertyValue("name", "大橘");
PropertyValue age = new PropertyValue("age", 1);
MutablePropertyValues propertyValues = new MutablePropertyValues(Arrays.asList(name, age));
beanDefinition.setPropertyValues(propertyValues);
// 手动注册
beanDefinitionRegistry.registerBeanDefinition("cat", beanDefinition);
}

@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
RootBeanDefinition beanDefinition = (RootBeanDefinition) beanFactory.getBeanDefinition("cat");
MutablePropertyValues propertyValues = beanDefinition.getPropertyValues();
System.out.println("原始年龄是: " + propertyValues.get("age"));
// 添加名为 age 的 property,但已经存在同名的 property,会以新加的为准
propertyValues.add("age", 2);
}
}

在重写的 postProcessBeanDefinitionRegistry() 方法中手动注册 Cat 类型、名为 cat 的 BeanDefinition,并添加了名为 age 的 property;在重写的 postProcessBeanFactory() 方法中获取名为 cat 的 BeanDefinition,然后添加同名的 property,新值将覆盖旧值。

1
2
3
4
5
6
7
8
9
10
@SpringBootApplication
public class A03ExtensionPoint {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(A03ExtensionPoint.class, args);
Cat cat = context.getBean(Cat.class);
System.out.println(cat.getName());
System.out.println(cat.getAge());
context.close();
}
}
原始年龄是: 1
大橘
2

3.3 相关的几个类

BeanDefinition 是什么?

postProcessBeanDefinitionRegistry() 方法的入参 BeanDefinitionRegistry 是什么?

postProcessBeanFactory() 方法的入参 ConfigurableListableBeanFactory 又是什么?

理解这些类的含义有助于更好地理解 Spring 拓展点。

BeanDefinition

BeanDefinition 意为“Bean 定义”,是用来定义 Bean 的。

Spring 容器中 Bean 的来源有多种,Bean 的类型又有多种,如何将这些不同来源、不同类型的 Bean 使用同一种方式注册到 Spring 容器中就成了个问题。

定义 BeanDefinition 类,它将不同的 Bean 信息进行抽象成 BeanDefinition 对象,在不同时机根据 BeanDefinition 对象对 Bean 进行实例化。

BeanDefinitionRegistry

BeanDefinitionRegistry 意为“Bean 定义注册器”,是用来注册 BeanDefinition 的。

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
public interface BeanDefinitionRegistry extends AliasRegistry {

/**
* 注册 BeanDefinition
*/
void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException;

/**
* 删除 BeanDefinition
*/
void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;

/**
* 获取 BeanDefinition
*/
BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;

/**
* 判断指定名称的 BeanDefinition 是否已经被注册
*/
boolean containsBeanDefinition(String beanName);

/**
* 获取所有 BeanDefinition 的名称
*/
String[] getBeanDefinitionNames();

/**
* 注册的 BeanDefinition 的数量
*/
int getBeanDefinitionCount();

/**
* 确定给定的 Bean 名称是否已在注册器中使用,即是否有本地 Bean 或别名在此名称下注册。
*/
boolean isBeanNameInUse(String beanName);

}

AliasRegistry 用于管理别名,作为 BeanDefinitionRegistry 的父类。

ConfigurableListableBeanFactory

ConfigurableListableBeanFactory 意为“可配置的列表 Bean 工厂”。所谓 Spring 容器,指的就是 BeanFactory,它提供了多种重载的 getBean() 方法用于获取 Bean,而 ConfigurableListableBeanFactoryBeanFactory 的一个子接口,可以认为它就是 Spring 容器。

在 Spring 中,其默认实现是 DefaultListableBeanFactory

DefaultListableBeanFactory的类图

它继承了很多接口,包括 ConfigurableListableBeanFactoryBeanDefinitionRegistry 等等。

3.4 实例化与执行

参考【2.3 实例化与执行】即可。

3.5 内置实现

BeanDefinitionRegistryPostProcessor 在 Spring 和 SpringBoot 中有众多内置实现,它们的大致逻辑都差不多,都是注册了一些特殊的 BeanDefinition

在 Spring 中有一个名为 ConfigurationClassPostProcessor 的实现类,用于解析 @Configuration 注解,可以参考 @Configuration 注解的那些事 一文。

4. Bean 后置处理器

4.1 拓展点的作用

Bean 后置处理器,即:BeanPostProcessor,它并非 SpringBoot 提供,是在 Spring 中就存在的:

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

/**
* 初始化前执行
*/
@Nullable
default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}

/**
* 初始化后执行
*/
@Nullable
default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}

}

它是 Bean 级别的后置处理器,在 Bean 实例化后执行。单例 Bean 被实例化后,最终会被缓存到 org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#singletonObjects 中,在实例化之后会进行初始化过程,包括属性填充、自定义初始化方法等,BeanPostProcessor 就是对这个阶段进行的拓展。

注意实例化和初始化的区别,实例化指的是 new 出一个对象,初始化指的是给 new 出的对象进行属性填充等操作。

BeanPostProcessor 提供了两个方法,分别是 postProcessBeforeInitialization()postProcessAfterInitialization(),前者将在 Bean 实例化后、初始化前执行,后者将在初始化后、自定义初始方法后执行。

BeanPostProcessor 与先前的所有拓展点都不同,并不是只执行一次,而是会作用于 Spring 管理的每个 Bean。

4.2 使用方式

实现 BeanPostProcessor 接口,重写抽象方法,并 将实现类交由 Spring 管理。

比如存在 Fish 类,采用配置类的方式将其交由 Spring 管理:

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
@Getter
@Setter
static class Fish implements InitializingBean {
private Double weight;
private Double price;

public Fish() {
System.out.println("1. 执行了无参构造");
}

@Override
public void afterPropertiesSet() throws Exception {
System.out.println("3. 执行了 afterPropertiesSet() 方法");
}

public void init() {
System.out.println("4. 执行了 init() 方法");
}
}

@Configuration
static class A04Configuration {
@Bean(name = "fish", initMethod = "init")
public Fish fish() {
return new Fish();
}
}

编写 BeanPostProcessor 的实现类,重写其中的抽象方法,当遇到名为 fish 的 Bean 时,执行一些特殊操作:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Component
static class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if ("fish".equals(beanName)) {
System.out.println("2. 执行了 postProcessBeforeInitialization() 方法");
}
return bean;
}

@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if ("fish".equals(beanName)) {
System.out.println("5. 执行了 postProcessAfterInitialization() 方法");
}
return bean;
}
}
1
2
3
4
5
6
7
@SpringBootApplication
public class A04ExtensionPoint {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(A04ExtensionPoint.class, args);
context.close();
}
}
1. 执行了无参构造
2. 执行了 postProcessBeforeInitialization() 方法
3. 执行了 afterPropertiesSet() 方法
4. 执行了 init() 方法
5. 执行了 postProcessAfterInitialization() 方法

4.3 注册与执行

前文中已经介绍过 AbstractApplicationContext#refresh() 方法了,BeanPostProcessor 的注册与执行也将围绕这个方法。

注册

AbstractApplicationContext#refresh() 方法中调用了 registerBeanPostProcessors() 方法,见名之意,该方法完成了 BeanPostProcessor 的注册。

它只是一个入口,真正的实现是:

1
org.springframework.context.support.PostProcessorRegistrationDelegate#registerBeanPostProcessors(org.springframework.beans.factory.config.ConfigurableListableBeanFactory, org.springframework.context.support.AbstractApplicationContext)

PostProcessorRegistrationDelegate 很熟悉,BeanFactoryPostProcessorBeanDefinitionRegistryPostProcessor 的执行也是使用的这个类中的方法。

registerBeanPostProcessors() 与前文介绍的 invokeBeanFactoryPostProcessors() 方法很类似,内部充满了注释,也告诉想要提交 PR 的开发者不要瞎重构。😂

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
public static void registerBeanPostProcessors(
ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {

// 首先获取所有 BeanPostProcessor 在 Spring 容器中的名称
String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);

// 注册 BeanPostProcessorChecker,当一个 Bean 在 BeanPostProcessor 实例化过程
// 中被创建时,即一个 Bean 不符合所有 BeanPostProcessor 的处理条件时,会记录一条日志
// 简单来说就是注册 BeanPostProcessorChecker 用来打印日志
int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));

// 将 BeanPostProcessor 分为三类,分别是实现了 PriorityOrdered、实现了
// Ordered 和其他的
List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
// 存放 MergedBeanDefinitionPostProcessor,它是 BeanPostProcessor 的一个子类
List<BeanPostProcessor> internalPostProcessors = new ArrayList<>();
List<String> orderedPostProcessorNames = new ArrayList<>();
List<String> nonOrderedPostProcessorNames = new ArrayList<>();
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);
}
}

// 首先注册实现了 PriorityOrdered 的 BeanPostProcessors
sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);

// 接下来注册实现了 Ordered 的 BeanPostProcessors
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);

// 然后执行所有常规的 BeanPostProcessors.
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);

// 最后,重新注册所有内部 BeanPostProcessors
sortPostProcessors(internalPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, internalPostProcessors);

// 重新注册后置处理器,以便将内部 Bean 检测为 ApplicationListeners,
// 将其移到处理器链的末端(用于拾取代理等)。
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
}

简单来说就是先获取容器中的所有 BeanPostProcessor,然后按照优先级分成三类再依次注册。

注册的逻辑采用 registerBeanPostProcessors() 方法实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
private static void registerBeanPostProcessors(
ConfigurableListableBeanFactory beanFactory,
List<? extends BeanPostProcessor> postProcessors) {

if (beanFactory instanceof AbstractBeanFactory abstractBeanFactory) {
// Bulk addition is more efficient against our CopyOnWriteArrayList there
abstractBeanFactory.addBeanPostProcessors(postProcessors);
}
else {
for (BeanPostProcessor postProcessor : postProcessors) {
beanFactory.addBeanPostProcessor(postProcessor);
}
}
}

调用 beanFactoryaddBeanPostProcessor() 方法完成 BeanPostProcessor 的注册,最终由 AbstractBeanFactory#addBeanPostProcessor() 实现真正的逻辑:

1
2
3
4
5
6
7
8
9
10
11
12
private final List<BeanPostProcessor> beanPostProcessors = new BeanPostProcessorCacheAwareList();

@Override
public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor) {
Assert.notNull(beanPostProcessor, "BeanPostProcessor must not be null");
synchronized (this.beanPostProcessors) {
// Remove from old position, if any
this.beanPostProcessors.remove(beanPostProcessor);
// Add to end of list
this.beanPostProcessors.add(beanPostProcessor);
}
}

执行

BeanPostProcessor 将在 Bean 实例化后,初始化前后执行,也就是说只要找到 Bean 实例化的位置,那 BeanPostProcessor 的执行时机也就在那附近了。

refresh() 方法中调用了 finishBeanFactoryInitialization() 方法:

1
2
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);

其上的注释:实例化所有剩余的非懒加载单例 Bean。

也就是说,这个方法将完成 Bean 的实例化。

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
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
// 初始化上下文的 conversion service
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));
}

// 如果之前没有注册任何 BeanFactoryPostProcessor,
// 比如 PropertySourcesPlaceholderConfigurer,那么注册默认的
// 嵌入值解析器用于注解属性值的解析
if (!beanFactory.hasEmbeddedValueResolver()) {
beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
}

// 尽早初始化 LoadTimeWeaverAware 以便尽早注册它们的转换器
String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
for (String weaverAwareName : weaverAwareNames) {
getBean(weaverAwareName);
}

// 停止使用临时 ClassLoader 进行类型匹配
beanFactory.setTempClassLoader(null);

// 允许缓存所有 BeanDefinition 元数据,不期待进一步更改
beanFactory.freezeConfiguration();

// 实例化所有剩余的非懒加载单例 Bean
beanFactory.preInstantiateSingletons();
}

显然,重点是最后调用 beanFactorypreInstantiateSingletons() 方法。

其默认实现是 DefaultListableBeanFactory

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
@Override
public void preInstantiateSingletons() throws BeansException {
if (logger.isTraceEnabled()) {
logger.trace("Pre-instantiating singletons in " + this);
}

// 对 copy 副本进行遍历,以允许 init 方法反过来注册新的 BeanDefinition
// 虽然这可能不是常规工厂启动的一部分,但在其他方面运行良好
List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

// 触发所有非懒加载单例 Bean 的初始化
for (String beanName : beanNames) {
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
if (isFactoryBean(beanName)) {
Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
if (bean instanceof SmartFactoryBean<?> smartFactoryBean && smartFactoryBean.isEagerInit()) {
getBean(beanName);
}
}
else {
getBean(beanName);
}
}
}

// 为所有适用的 Bean 触发后置初始化回调
for (String beanName : beanNames) {
Object singletonInstance = getSingleton(beanName);
if (singletonInstance instanceof SmartInitializingSingleton smartSingleton) {
StartupStep smartInitialize = getApplicationStartup().start("spring.beans.smart-initialize")
.tag("beanName", beanName);
smartSingleton.afterSingletonsInstantiated();
smartInitialize.end();
}
}
}

总体来说分成两部分:

  1. 触发所有非懒加载单例 Bean 的初始化,使用 getBean() 实现
  2. 为所有适用的 Bean 触发后置初始化回调,即调用 SmartInitializingSingletonafterSingletonsInstantiated() 方法(这个拓展点在后续会讲到)

getBean() 的流程很长,也不是本文的重点, 后续另开一文详细分析, 此处仅着重分析要点:

1
2
3
4
@Override
public Object getBean(String name) throws BeansException {
return doGetBean(name, null, null, false);
}

调用了 doGetBean() 方法,这个方法贼长,重点是调用的 createBean() 方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
protected <T> T doGetBean(
String name, @Nullable Class<T> requiredType,
@Nullable Object[] args, boolean typeCheckOnly) throws BeansException {

// --snip--

// 创建 Bean 实例
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
destroySingleton(beanName);
throw ex;
}
});
beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}

// --snip--
}

其默认实现是 AbstractAutowireCapableBeanFactory#createBean()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
// --snip--

try {
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
if (logger.isTraceEnabled()) {
logger.trace("Finished creating instance of bean '" + beanName + "'");
}
return beanInstance;
}
// --snip--
}

重点是调用的 doCreateBean() 方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
protected Object doCreateBean(String beanName, 
RootBeanDefinition mbd,
@Nullable Object[] args) throws BeanCreationException {

// Instantiate the bean.
// 实例化 Bean

// Allow post-processors to modify the merged bean definition.
// 允许后置处理器修改合并的 BeanDefinition

// Eagerly cache singletons to be able to resolve circular references
// even when triggered by lifecycle interfaces like BeanFactoryAware.
// 尽快缓存单例 Bean,以便触发生命周期接口(像 BeanFactoryAware)时也能解决循环依赖

// 初始化 Bean 实例
Object exposedObject = bean;
try {
populateBean(beanName, mbd, instanceWrapper);
exposedObject = initializeBean(beanName, exposedObject, mbd);
}

// --snip--
}

在这个方法中完成了 Bean 的实例和初始化,初始化操作由 initializeBean() 方法完成。BeanPostProcessor 会在 Bean 初始化前后执行,不妨大胆猜测就是在 initializeBean() 方法中完成 BeanPostProcessor 的执行:

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 Object initializeBean(String beanName, 
Object bean, @Nullable RootBeanDefinition mbd) {
// 执行一些 Aware 方法
invokeAwareMethods(beanName, bean);

Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
// 应用 BeanPostProcessor 的 postProcessBeforeInitialization() 方法
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}

try {
// 执行初始化方法
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null), beanName, ex.getMessage(), ex);
}
if (mbd == null || !mbd.isSynthetic()) {
// 应用 BeanPostProcessor 的 postProcessAfterInitialization
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}

return wrappedBean;
}

查看源码后也是验证了猜想,选取 applyBeanPostProcessorsBeforeInitialization() 方法进行解析:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Override
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean,
String beanName)
throws BeansException {

Object result = existingBean;
for (BeanPostProcessor processor : getBeanPostProcessors()) {
Object current = processor.postProcessBeforeInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}

逻辑很简单,获取所有 BeanPostProcessor 后进行遍历,依次执行它们的 postProcessBeforeInitialization() 方法。那 BeanPostProcessor 是怎么获取的呢?

1
2
3
public List<BeanPostProcessor> getBeanPostProcessors() {
return this.beanPostProcessors;
}

调用的是 AbstractBeanFactory#getBeanPostProcessors() 方法,直接返回成员变量 beanPostProcessors 的值,这里和前文中注册 BeanPostProcessor 的逻辑串联了起来。

4.4 内置实现与使用场景

内置实现举例

SpringBoot 进行参数校验时会使用到 BeanValidationPostProcessor,它也是 BeanPostProcessor 的一种内置实现。

更多使用场景

有时可能会编写一些自定义注解将它们标记到相应的类上,希望在对应的 Bean 实例化后,根据标记的自定义注解执行特定的逻辑,此时就可以通过实现 BeanPostProcessor 完成。

4.5 更多思考

BeanPostProcessor 能够在 Bean 初始化前后被调用,那如果要在 Bean 实例化前后进行拓展应该怎么办呢?

5. 实例化感知 Bean 后置处理器

5.1 拓展点的作用

实例化感知 Bean 后置处理器,即:InstantiationAwareBeanPostProcessor,它并非 SpringBoot 提供,是在 Spring 中就存在的:

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
public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor {

/**
* Bean 实例化前执行
*/
@Nullable
default Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
return null;
}

/**
* Bean 实例化后执行
*/
default boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
return true;
}

/**
* 实例化完成后,属性注入时(准确地说是属性注入前)执行
*/
@Nullable
default PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName)
throws BeansException {

return pvs;
}

}

可以看到,InstantiationAwareBeanPostProcessor 继承了 BeanPostProcessor,并额外提供了三个方法,能够分别在 Bean 实例化前、实例化后、属性注入阶段进行拓展。

InstantiationAwareBeanPostProcessorBeanPostProcessor 类似,会作用于 Spring 管理的每个 Bean。

5.2 使用方法

实现 InstantiationAwareBeanPostProcessor 接口,重写抽象方法,并 将实现类交由 Spring 管理。

比如存在 DependenceExample 类,将t它们交由 Spring 管理,并在 Example 中注入 Dependence

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
@Getter
@Setter
static class Example {
private String str = "example";
private Dependence dependence;

@Autowired
public void setDependence(Dependence dependence) {
System.out.println("6. Example 注入 dependence");
this.dependence = dependence;
}

public void setStr(String str) {
System.out.println("7. Example 注入 str");
this.str = str;
}

public Example() {
System.out.println("3. 执行了 Example 的无参构造");
}

public void init() {
System.out.println("9. 执行了 init() 方法");
}
}

@Configuration
static class A05Configuration {
@Bean(initMethod = "init", value = EXAMPLE_BEAN_NAME)
public Example example() {
return new Example();
}
}

@Component
static class Dependence {
public Dependence() {
System.out.println("1. 执行了 Dependence 的无参构造");
}
}

编写 InstantiationAwareBeanPostProcessor 的实现类,重写其中所有抽象方法(包括父接口 BeanPostProcessor 中的方法),当遇到名为 a05-example 的 Bean 时,执行一些特殊操作:

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
@Component
static class MyInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
if (EXAMPLE_BEAN_NAME.equals(beanName)) {
System.out.println("2. 执行了 postProcessBeforeInstantiation() 方法");
}
// 是否返回其他 Bean 实例?可以返回代理对象,阻止默认实例化
return null;
}

@Override
public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
if (EXAMPLE_BEAN_NAME.equals(beanName)) {
System.out.println("4. 执行了 postProcessAfterInstantiation() 方法");
}
// 是否需要依赖注入,如果返回 false,则不再执行 postProcessProperties() 方法;
return true;
}

@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
if (EXAMPLE_BEAN_NAME.equals(beanName)) {
System.out.println("5. 执行了 postProcessProperties() 方法");
MutablePropertyValues propertyValues = (MutablePropertyValues) pvs;
propertyValues.add("str", "str");
}
return pvs;
}

@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (EXAMPLE_BEAN_NAME.equals(beanName)) {
System.out.println("8. 执行了 postProcessBeforeInitialization() 方法");
}
return bean;
}

@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (EXAMPLE_BEAN_NAME.equals(beanName)) {
System.out.println("10. 执行了 postProcessAfterInitialization() 方法");
}
return bean;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
@SpringBootApplication
public class A05ExtensionPoint {

private static final String EXAMPLE_BEAN_NAME = "a05-example";

public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(A05ExtensionPoint.class, args);
Assert.isTrue(context.getBean(Example.class).getStr().equals("str"), "");
Assert.isTrue(context.getBean(Example.class).getDependence().equals(context.getBean(Dependence.class)), "");
context.close();
}
}
1. 执行了 Dependence 的无参构造
2. 执行了 postProcessBeforeInstantiation() 方法
3. 执行了 Example 的无参构造
4. 执行了 postProcessAfterInstantiation() 方法
5. 执行了 postProcessProperties() 方法
6. Example 注入 dependence
7. Example 注入 str
8. 执行了 postProcessBeforeInitialization() 方法
9. 执行了 init() 方法
10. 执行了 postProcessAfterInitialization() 方法

InstantiationAwareBeanPostProcessor 之于 BeanPostProcessor,就好比 BeanDefinitionRegistryPostProcessor 之于 BeanFactoryPostProcessor,这里的比较主要是在执行时机上。

InstantiationAwareBeanPostProcessor 将在 BeanPostProcessor 前执行,对于增加的三个方法有:

  • postProcessBeforeInstantiation():该方法将在 Bean 实例化前被执行。该方法有 Object 类型的返回值,可以自定义 Bean 替换原有的 Bean(比如进行了动态代理),在替换原有 Bean 后,将执行 postProcessAfterInstantiation(),其他拓展点将不再触发;
  • postProcessAfterInstantiation():该方法将在 Bean 实例化后被执行。该方法有 boolean 类型的返回值,它表示是否需要依赖注入,如果返回 false,将不再执行 InstantiationAwareBeanPostProcessor 实例中的其他任何拓展方法(包括父类 BeanPostProcessor 中的方法);
  • postProcessProperties():该方法将在 Bean 实例化后、属性注入前执行。在此方法中可以对注入的属性值进行更改,或替换原来的属性值。默认情况下直接返回传入的 PropertyValues,如果返回 null 将跳过后续的属性填充。

5.3 注册

InstantiationAwareBeanPostProcessorBeanPostProcessor 的子接口,因此它的注册方式与 BeanPostProcessor 的注册方式一样,参考【4.3 注册与执行】。

5.4 执行

postProcessBeforeInstantiation()

InstantiationAwareBeanPostProcessor 的第一个方法 postProcessBeforeInstantiation() 将在 Bean 实例化前执行,结合上一节的内容,可以猜到这个方法的执行与 refresh() 方法中调用的 finishBeanFactoryInitialization() 方法有关。

大致流程与上一节类似,跟随相同的流程来到 AbstractAutowireCapableBeanFactory#createBean() 方法中:

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
@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {

// --snip--

try {
// 让 BeanPostProcessors 有机会返回代理而不是目标 Bean 实例
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
// 如果返回的值不为 null,直接返回,后续操作不再执行
if (bean != null) {
return bean;
}
}

try {
// 上一节中分析过的方法
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
if (logger.isTraceEnabled()) {
logger.trace("Finished creating instance of bean '" + beanName + "'");
}
return beanInstance;
}

// --snip--
}

在这个方法中调用了 resolveBeforeInstantiation() 方法,这个方法能够在 Bean 实例化前做一些操作:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@Nullable
protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
Object bean = null;
// 对应的 BeanDefinition 还未执行过实例化前的操作
if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
// 确保 Bean 在这一点上得到了真正的解析
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
// 确定给定的 BeanDefinition 的模板类型
Class<?> targetType = determineTargetType(beanName, mbd);
if (targetType != null) {
// 获取所有 InstantiationAwareBeanPostProcessor,一一遍历执行实例化前的操作
bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
if (bean != null) {
// 如果上一步返回的不是 null,直接执行实例化后的操作
bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
}
}
}
mbd.beforeInstantiationResolved = (bean != null);
}
return bean;
}

postProcessBeforeInstantiation() 方法返回非 null 的值时,会立即执行 postProcessAfterInstantiation() 方法,而在 AbstractAutowireCapableBeanFactory#createBean() 方法中,resolveBeforeInstantiation() 方法返回的值不为 null 时,将直接返回,不再执行后续的 doCreateBean() 方法,也就是不再执行其他拓展点,Spring 将 Bean 实例化及其以后的所有操作都交给实现者。

applyBeanPostProcessorsBeforeInstantiation() 方法的实现也有点意思:

1
2
3
4
5
6
7
8
9
10
@Nullable
protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {
for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
Object result = bp.postProcessBeforeInstantiation(beanClass, beanName);
if (result != null) {
return result;
}
}
return null;
}

获取 InstantiationAwareBeanPostProcessor 的方式通过 getBeanPostProcessorCache().instantiationAware 完成,getBeanPostProcessorCache() 返回了 BeanPostProcessor 实例的缓存(还分了类),以便多次重复获取 BeanPostProcessor

postProcessAfterInstantiation()postProcessProperties()

这个方法将会在 Bean 实例化之后 执行,大胆猜测很有可能在 doCreateBean() 方法中执行,这在前文已经分析过一部分:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
protected Object doCreateBean(String beanName, 
RootBeanDefinition mbd,
@Nullable Object[] args) throws BeanCreationException {

// Instantiate the bean.
// 实例化 Bean

// Allow post-processors to modify the merged bean definition.
// 允许后置处理器修改合并的 BeanDefinition

// Eagerly cache singletons to be able to resolve circular references
// even when triggered by lifecycle interfaces like BeanFactoryAware.
// 尽快缓存单例 Bean,以便触发生命周期接口(像 BeanFactoryAware)时也能解决循环依赖

// 初始化 Bean 实例
Object exposedObject = bean;
try {
populateBean(beanName, mbd, instanceWrapper);
exposedObject = initializeBean(beanName, exposedObject, mbd);
}

// --snip--
}

前文分析的是其中的 initializeBean() 方法,这个方法完成了 Bean 的初始化。

在计算机的英语表述中,populate 常被翻译为“填充”,populateBean() 方法将使用 BeanDefinition 中的属性值填充 BeanWrapper 中的 Bean 实例。

也就是说,这个方法会被 Bean 实例进行一些操作,点进去看看:

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
protected void populateBean(String beanName, 
RootBeanDefinition mbd,
@Nullable BeanWrapper bw) {
// --snip--

// 在设置属性前,让任何 InstantiationAwareBeanPostProcessors 都有机会修改 Bean,
// 这样使用后,可以用于支持字段注入
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
if (!bp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
// 如果返回的是 false,直接返回,不再执行后续逻辑
return;
}
}
}

// --snip--

if (hasInstantiationAwareBeanPostProcessors()) {
if (pvs == null) {
pvs = mbd.getPropertyValues();
}
// 获取所有 InstantiationAwareBeanPostProcessor,一一遍历执行属性注入前的操作
for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
PropertyValues pvsToUse = bp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
// 如果返回 null,直接返回,跳过后续的属性填充
if (pvsToUse == null) {
return;
}
pvs = pvsToUse;
}
}

// --snip--
}

在这个方法中,执行了 InstantiationAwareBeanPostProcessor 中的第二、第三个拓展方法,这些拓展方法返回特殊的返回值时,会跳过后续逻辑的执行。

5.5 内置实现

InstantiationAwareBeanPostProcessor 的实现十分有用,在 Spring 中也一个名为 AutowiredAnnotationBeanPostProcessor 的实现:

AutowiredAnnotationBeanPostProcessor的类图

AutowiredAnnotationBeanPostProcessor 用于解析 Bean 属性注入的相关注解,比如 @Autowired@Value 注解的解析。

Bean 中的字段被 @Autowired 注解标记后,可以将 Spring 容器中对应类型的 Bean 注入到当前 Bean 中,其实现逻辑就在重写的 postProcessProperties() 方法中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Override
public PropertyValues postProcessProperties(PropertyValues pvs,
Object bean, String beanName) {
// 获取注入元数据
InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
try {
// 根据解析出的元数据完成注入
metadata.inject(bean, beanName, pvs);
}
catch (BeanCreationException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
}
return pvs;
}

AutowiredAnnotationBeanPostProcessor 实现了 SmartInstantiationAwareBeanPostProcessor 接口,后者则继承了 InstantiationAwareBeanPostProcessor,那 SmartInstantiationAwareBeanPostProcessor 又是何方神圣?

6. 智能实例化感知 Bean 后置处理器

6.1 拓展点的作用

智能实例化感知 Bean 后置处理器,即:SmartInstantiationAwareBeanPostProcessor,它并非 SpringBoot 提供,是在 Spring 中就存在的:

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
public interface SmartInstantiationAwareBeanPostProcessor extends InstantiationAwareBeanPostProcessor {

/**
* 预测从该处理器的 postProcessBeforeInstantiation() 回调中最终返回的 Bean 类型
* 默认返回 null。具体实现应尽量预测已知、已缓存的 Bean 类型,而无需额外的处理步骤。
*
* @return Bean 的类型,如果无法预测就返回 null
*/
@Nullable
default Class<?> predictBeanType(Class<?> beanClass, String beanName) throws BeansException {
return null;
}

/**
* 确定从该处理器的 postProcessBeforeInstantiation() 回调中最终返回的 Bean 类型
* 默认实现会按原样返回给定的 Bean 类。具体实现应全面评估其处理步骤,以便预先创建、初
* 始化潜在的代理类。
*
* @return Bean 的类型,永不为 null
* @since 6.0
*/
default Class<?> determineBeanType(Class<?> beanClass, String beanName) throws BeansException {
return beanClass;
}

/**
* 确定创建给定 Bean 时使用的候选构造方法,默认实现返回 null。
*
* @return 候选的构造器,如果没特殊指定,则返回 null,采用默认构造器
*/
@Nullable
default Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, String beanName)
throws BeansException {

return null;
}

/**
* 返回一个引用,以便尽早访问指定的 Bean,这个方法通常用于解决循环引用。
* 此回调为后置处理器提供了提前暴露 wrapper 的机会,即在目标 Bean 实例完全初始化之前。
* 暴露的对象应等同于 postProcessBeforeInitialization() 或 postProcessAfterInitialization()
* 所暴露的对象。请注意,除非后置处理器从上述回调中返回不同的 wrapper,否则
* 此方法返回的对象将用作 Bean 引用。
* 默认实现是按原样返回给定的 Bean。
*/
default Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
return bean;
}

}

可以看到,SmartInstantiationAwareBeanPostProcessor 继承了 InstantiationAwareBeanPostProcessor,并额外提供了四个方法,其中 determineBeanType() 方法是在 Spring 6.0 中新增的。

在类注释上有一段 NOTE,简单来说就是:SmartInstantiationAwareBeanPostProcessor 接口是一个专用接口,主要在框架内部使用。一般情况下,日常开发中实现 BeanPostProcessor 接口即可。

6.2 使用方式

存在名为 Student 的类,它依赖了 Teacher

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
@Component(value = STUDENT_BEAN_NAME)
static class Student {
@Getter
@Setter
private String name = "mofan";

@Getter
@Autowired
private Teacher teacher;

public Student() {
System.out.println("Student 的无参数构造方法被执行");
}

public Student(String name) {
this.name = name;
System.out.println("Student 的有参数构造方法(name)被执行");
}

public Student(Teacher teacher) {
this.teacher = teacher;
System.out.println("Student 的有参数构造方法(teacher)被执行");
}

public Student(String name, Teacher teacher) {
this.name = name;
this.teacher = teacher;
System.out.println("Student 的有参数构造方法(name,teacher)被执行");
}

public void setTeacher(Teacher teacher) {
System.out.println("----student中的setTeacher方法被调用");
this.teacher = teacher;
}
}

存在名为 Teacher 的类,它内部依赖了 Student,构成了循环依赖:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Component
static class Teacher {
@Getter
@Setter
private String name = "Mr.Chen";

@Getter
@Autowired
private Student student;

public Teacher() {
System.out.println("Teacher 的无参数构造方法被执行");
}

public void setStudent(Student student) {
System.out.println("Teacher 中的 setStudent 方法被调用");
this.student = student;
}
}

实现 SmartInstantiationAwareBeanPostProcessor 接口,选择性重写其中的方法,并将实现类交由 Spring 管理:

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
@Component
static class MySmartInstantiationAwareBeanPostProcessor implements SmartInstantiationAwareBeanPostProcessor {
@Override
public Class<?> predictBeanType(Class<?> beanClass, String beanName) throws BeansException {
if (STUDENT_BEAN_NAME.equals(beanName)) {
System.out.println("predictBeanType 方法被执行");
return Student.class;
}
return null;
}

@Override
public Class<?> determineBeanType(Class<?> beanClass, String beanName) throws BeansException {
if (STUDENT_BEAN_NAME.equals(beanName)) {
System.out.println("determineBeanType 方法被执行");
}
return beanClass;
}

@Override
public Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, String beanName) throws BeansException {
if (STUDENT_BEAN_NAME.equals(beanName)) {
// 四个构造方法,选默认构造方法
// 选(name)时会报错,选(teacher)时会有循环依赖,并且是 Spring 无法解决的循环依赖
// 选(name, teacher)时也会报错
System.out.println("determineCandidateConstructors 方法被执行");
return new Constructor[]{beanClass.getConstructors()[0]};
}
return null;
}

@Override
public Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
if (STUDENT_BEAN_NAME.equals(beanName)) {
System.out.println("getEarlyBeanReference 方法被执行");
}
return bean;
}

@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
if (STUDENT_BEAN_NAME.equals(beanName)) {
System.out.println("postProcessBeforeInstantiation 方法被执行");
}
return null;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
@SpringBootApplication
public class A06ExtensionPoint {

private static final String STUDENT_BEAN_NAME = "a06-student";

public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(A06ExtensionPoint.class);
Teacher teacher = context.getBean(Teacher.class);
System.out.println(teacher.getClass().getName());
Student student = context.getBean(Student.class);
System.out.println(student.getClass().getName());
context.close();
}
}
predictBeanType 方法被执行
postProcessBeforeInstantiation 方法被执行
determineCandidateConstructors 方法被执行
Student 的无参数构造方法被执行
predictBeanType 方法被执行
Teacher 的无参数构造方法被执行
predictBeanType 方法被执行
predictBeanType 方法被执行
getEarlyBeanReference 方法被执行

省略了许多 predictBeanType 方法被执行 的打印。

6.3 注册

SmartInstantiationAwareBeanPostProcessorBeanPostProcessor 的子接口,因此它的注册方式与 BeanPostProcessor 的注册方式一样,参考【4.3 注册与执行】。

6.4 执行

此处只介绍 determineCandidateConstructors() 方法的执行时间,该方法用于确定候选构造器,在实例化 Bean 使用。

在前文的介绍中可知,在 getBean() 方法里会对 Bean 进行实例化。跟随前文的步骤,来到 AbstractAutowireCapableBeanFactory#doCreateBean() 方法中:

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 Object doCreateBean(String beanName, 
RootBeanDefinition mbd,
@Nullable Object[] args) throws BeanCreationException {

// Instantiate the bean.
// 实例化 Bean
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
Object bean = instanceWrapper.getWrappedInstance();
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
}

// Allow post-processors to modify the merged bean definition.
// 允许后置处理器修改合并的 BeanDefinition

// Eagerly cache singletons to be able to resolve circular references
// even when triggered by lifecycle interfaces like BeanFactoryAware.
// 尽快缓存单例 Bean,以便触发生命周期接口(像 BeanFactoryAware)时也能解决循环依赖

// 初始化 Bean 实例
// Initialize the bean instance.

// --snip--
}

首先就是实例化 Bean,其中调用了 createBeanInstance() 方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
protected BeanWrapper createBeanInstance(String beanName, 
RootBeanDefinition mbd,
@Nullable Object[] args) {
// --snip--

// Candidate constructors for autowiring?
// Autowired 使用的构造器
Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
return autowireConstructor(beanName, mbd, ctors, args);
}

// Preferred constructors for default construction?
// 默认构造的首选构造器
ctors = mbd.getPreferredConstructors();
if (ctors != null) {
return autowireConstructor(beanName, mbd, ctors, null);
}

// No special handling: simply use no-arg constructor.
// 没有特殊处理:简单使用无参构造器
return instantiateBean(beanName, mbd);
}

调用了 determineConstructorsFromBeanPostProcessors() 方法,如果存在被 @Autowired 注解标记的构造器时,就使用这个构造器来实例化 Bean。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Nullable
protected Constructor<?>[] determineConstructorsFromBeanPostProcessors(@Nullable Class<?> beanClass, String beanName)
throws BeansException {

if (beanClass != null && hasInstantiationAwareBeanPostProcessors()) {
for (SmartInstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().smartInstantiationAware) {
Constructor<?>[] ctors = bp.determineCandidateConstructors(beanClass, beanName);
if (ctors != null) {
return ctors;
}
}
}
return null;
}

可以看到,就是在此处调用了 determineCandidateConstructors() 方法。

6.5 内置实现

AutowiredAnnotationBeanPostProcessor 为例。

predictBeanType()

AutowiredAnnotationBeanPostProcessor 中并未重写 predictBeanType() 方法。

在 Spring AOP 中,AbstractAutoProxyCreator 重写了 predictBeanType() 方法,这与 AOP 的实现有关,此处不再深究, 后续另开一文详细分析

determineBeanType()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Override
public Class<?> determineBeanType(Class<?> beanClass, String beanName) throws BeanCreationException {
// 检查被 @Lookup 注解标记的方法
checkLookupMethods(beanClass, beanName);

// Pick up subclass with fresh lookup method override from above
// 根据上述子类重写 @Lookup 标记的方法
if (this.beanFactory instanceof AbstractAutowireCapableBeanFactory aacBeanFactory) {
RootBeanDefinition mbd = (RootBeanDefinition) this.beanFactory.getMergedBeanDefinition(beanName);
// 没有工厂方法,但是制定了 Bean 的 Class
if (mbd.getFactoryMethodName() == null && mbd.hasBeanClass()) {
// 获取给定 Bean 的实际 Class
return aacBeanFactory.getInstantiationStrategy().getActualBeanClass(mbd, beanName, aacBeanFactory);
}
}
return beanClass;
}

determineCandidateConstructors()

重写的 determineCandidateConstructors() 方法很长,简单来说就是遍历类中所有构造器,然后选取出候选构造器。该方法中有这样一段:

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
@Override
@Nullable
public Constructor<?>[] determineCandidateConstructors(Class<?> beanClass,
final String beanName)
throws BeanCreationException {
// --snip--
for (Constructor<?> candidate : rawCandidates) {
// --snip--
// 获取构造器上与 Autowired 有关的注解
MergedAnnotation<?> ann = findAutowiredAnnotation(candidate);
if (ann == null) {
// 处理注解信息为 null 的情况
}
if (ann != null) {
// 第一次走到这时 requiredConstructor 等于 null
if (requiredConstructor != null) {
// 必需的构造器只能有一个,否则抛出异常
throw new BeanCreationException();
}
// 确定被标记的构造方法是否是必需的
boolean required = determineRequiredStatus(ann);
if (required) {
// 只能有一个,多个就抛异常
if (!candidates.isEmpty()) {
throw new BeanCreationException();
}
// 确定必需的构造器
requiredConstructor = candidate;
}
// 添加到候选项列表中
candidates.add(candidate);
}
else if (candidate.getParameterCount() == 0) {
defaultConstructor = candidate;
}
}
// --snip--
return (candidateConstructors.length > 0 ? candidateConstructors : null);
}

遍历构造器时,使用 findAutowiredAnnotation() 方法查看构造器上是否有指定注解,如果有指定注解,并且使用 determineRequiredStatus() 方法求得注解标记的构造器是必需的,那么当前构造器就是必需的构造器。

1
2
3
4
5
6
7
8
9
10
11
@Nullable
private MergedAnnotation<?> findAutowiredAnnotation(AccessibleObject ao) {
MergedAnnotations annotations = MergedAnnotations.from(ao);
for (Class<? extends Annotation> type : this.autowiredAnnotationTypes) {
MergedAnnotation<?> annotation = annotations.get(type);
if (annotation.isPresent()) {
return annotation;
}
}
return null;
}

对构造器而言,遍历 this.autowiredAnnotationTypes 的值,查看构造器是否被这些注解标记。this.autowiredAnnotationTypes 的值在构造 AutowiredAnnotationBeanPostProcessor 实例时被指定,默认有以下四个值:

  • @org.springframework.beans.factory.annotation.Autowired
  • @org.springframework.beans.factory.annotation.Value
  • @jakarta.inject.Inject
  • @javax.inject.Inject
1
2
3
4
protected boolean determineRequiredStatus(MergedAnnotation<?> ann) {
return (ann.getValue(this.requiredParameterName).isEmpty() ||
this.requiredParameterValue == ann.getBoolean(this.requiredParameterName));
}

该方法用于判断给定注解是否配置了 require。比如以 @Autowired 注解,该注解有 require 属性,同时该属性值为 true 时,determineRequiredStatus() 方法返回 true;以 @Value 注解来说,它不含 requireoptional 属性,determineRequiredStatus() 方法也返回 true

getEarlyBeanReference()

AutowiredAnnotationBeanPostProcessor 中并未重写 getEarlyBeanReference() 方法。

在 Spring AOP 中,AbstractAutoProxyCreator 重写了 predictBeanType() 方法,这与 AOP 的实现有关,此处不再深究, 后续另开一文详细分析

7. 应用上下文感知

7.1 拓展点的作用

应用上下文感知,即:ApplicationContextAware,它并非 SpringBoot 提供,是在 Spring 中就存在的:

1
2
3
4
5
6
7
8
public interface ApplicationContextAware extends Aware {

/**
* 获取 ApplicationContext,这通常用于设置某个 Bean 中 ApplicationContext 类型的字段值
*/
void setApplicationContext(ApplicationContext applicationContext) throws BeansException;

}

该接口实现了 Aware 接口,提供了 setApplicationContext() 方法,用于获取 ApplicationContext,通常用于设置某个 Bean 中 ApplicationContext 类型的字段值。

Aware 接口是一个标记接口,Spring 中提供了众多的 Aware 接口,这些接口中都有以 set 开头的方法,用于获取特定的对象。比如:

  • EnvironmentAware:获取 Environment 对象,该对象可用于获得系统内所有的参数,也可以通过注入的方式获取该对象;
  • EmbeddedValueResolverAware:获取 StringValueResolver 对象,该对象可用于获取 String 类型的 property,也可以通过 @Value 注解获取 String 类型的 property;
  • ResourceLoaderAware:获取 ResourceLoader 对象,该对象可用于获取 classpath 下的所有资源;
  • ApplicationEventPublisherAware:获取 ApplicationEventPublisher 对象,该对象可用于发送事件,也可以通过注入的方式获取该对象;
  • MessageSourceAware:获取 MessageSource 对象,该对象可用于获取国际化信息;
  • ApplicationStartupAware:获取 ApplicationStartup 对象,该对象可用于获取 Spring 启动期间各个步骤的信息。

Aware 的子接口其实有很多,那为什么只列举上面那些呢?

因为 上面这些 Aware 接口都由 ApplicationContextAwareProcessor 处理。

7.2 使用方式

ApplicationContextAware 接口为例,实现 ApplicationContextAware 接口,重写 setApplicationContext() 方法,并将实现类交由 Spring 管理。

除此之外,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
/**
* <p>
* 类似的接口还有:
* <ul>
* <li>EnvironmentAware</li>
* <li>EmbeddedValueResolverAware</li>
* <li>ResourceLoaderAware</li>
* <li>ApplicationEventPublisherAware</li>
* <li>MessageSourceAware</li>
* <li>ApplicationStartupAware</li>
* </ul>
* </p>
*/
@Component
static class MyApplicationContextAware implements ApplicationContextAware {
private ApplicationContext applicationContext;

@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
System.out.println("2. Spring 上下文 ApplicationContext 被注入");
}
}

@Component
static class MyApplicationContext {
private ApplicationContext applicationContext;

@Autowired
public void setApplicationContext(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
System.out.println("1. 使用 @Autowired 注入 ApplicationContext");
}
}
1
2
3
4
5
6
7
@SpringBootApplication
public class A07ExtensionPoint {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(A07ExtensionPoint.class, args);
context.close();
}
}
1. 使用 @Autowired 注入 ApplicationContext
2. Spring 上下文 ApplicationContext 被注入

可以看到,相比于通过 ApplicationContextAware 获取 ApplicationContext 对象,直接注入 ApplicationContext 会更早执行。

7.3 注册与执行

可以使用 ApplicationContextAware 获取 ApplicationContext 对象,也可以直接注入 ApplicationContext,它们有什么区别呢?

ApplicationContextAware 接口由 ApplicationContextAwareProcessor 处理,后者实现了 BeanPostProcessor 接口并重写 postProcessBeforeInitialization() 方法,在 Bean 初始化前处理继承了 ApplicationContextAware 接口的 Bean,但 ApplicationContextAwareProcessor 并未被 @Component 等注解标记,那它是怎么添加到 Spring 容器中的呢?

这些问题在 获取 ApplicationContext 一文中可以获得准确答案,此处不再赘述。

7.4 一个重要的细节

ApplicationContextAwareProcessor 被加载的时机

ApplicationContextAwareProcessor 将在准备 BeanFactory 时被加载,也就在 refresh() 方法中的 prepareBeanFactory() 方法中被加载:

flowchart TD
1("SpringApplication#refresh()")
2("AbstractApplicationContext#refresh()")
3("AbstractApplicationContext#prepareBeanFactory()")

1 --> 2 --> 3

这一步是十分靠前的。

其他 BeanPostProcessor 相比于 ApplicationContextAwareProcessor 的注册时机

ApplicationContextAwareProcessor 实现了 BeanPostProcessor 接口,重写了其中的 postProcessBeforeInitialization() 方法, 会在 Bean 实例化后、初始化前执行。

回忆 BeanPostProcessor 的注册时机,它是在 refresh() 方法中的 registerBeanPostProcessors() 方法中被注册的。refresh() 方法中的部分流程如下:

flowchart TD
1("prepareRefresh()")
2("obtainFreshBeanFactory")
subgraph 3 ["prepareBeanFactory()"]
3.1("加载 ApplicationContextAwareProcessor")
end
4("postProcessBeanFactory()")
subgraph 5 ["invokeBeanFactoryPostProcessors()"]
5.1("执行 BeanFactoryPostProcessor")
end
subgraph 6 ["registerBeanPostProcessors()"]
6.1("注册 BeanPostProcessor")
end
7("...")

1 --> 2 --> 3 --> 4 --> 5 --> 6 --> 7

在注册其他 BeanPostProcessor 前,容器中已经存在了 ApplicationContextAwareProcessor 类型的 BeanPostProcessor

直接注入 ApplicationContext 的实现

注入 ApplicationContext 时会使用 @Autowired@Resource 注解,前者由 AutowiredAnnotationBeanPostProcessor 实现,后者由 CommonAnnotationBeanPostProcessor 实现,它们都是 BeanPostProcessor 的实现, 它们实例化的时机是在 registerBeanPostProcessors() 方法中,相比于 ApplicationContextAwareProcessor 的实例化时机更加靠后。

这说明了什么呢?

也就是说,如果想要在 registerBeanPostProcessors() 方法前创建的 Bean 中拿到 ApplicationContext 实例,只能通过实现 ApplicationContextAware 接口完成,而不能通过注入 ApplicationContext 获取,因为那时还没加载用于解析相关注解的 BeanPostProcessor

比如在 BeanFactoryPostProcessor 的实现类中获取 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
@Component
static class MyFirstBeanFactoryPostProcessor implements BeanFactoryPostProcessor {

@Autowired
private ApplicationContext context;

@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
Assert.isNull(context, "依赖注入的 ApplicationContext 不是 null");
}
}

@Component
static class MySecondBeanFactoryPostProcessor implements BeanFactoryPostProcessor, ApplicationContextAware {

private ApplicationContext context;

@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
Assert.notNull(context, "使用 ApplicationContextAware 注入的 ApplicationContext 为 null");
}

@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.context = applicationContext;
}
}

BeanFactoryPostProcessor 将在 invokeBeanFactoryPostProcessors() 方法中完成实例化与执行,实例化是通过 getBean() 方法完成的,如果容器中存在指定名称的 Bean,就直接获取,否则先创建再获取,这在前文已经说过了。

在通过 getBean() 实例化 BeanFactoryPostProcessor 前,会获取当前容器中的所有 BeanPostProcessor 实例,并执行它们的 postProcessBeforeInitialization() 方法,此时容器中存在 ApplicationContextAwareProcessor 类型的 BeanPostProcessor,使得实现 ApplicationContextAware 接口的 Bean 能够拿到 ApplicationContext 实例,而利用注入方式获取的 ApplicationContext 实例,由于还未加载相关的解析类,因此注入是无效的。

7.5 另一个 Aware

除了使用 ApplicationContextAwareProcessor 处理的一众 Aware 外,还有一个名为 BeanNameAware 的接口,它提供了获取某个 Bean 的 name 的能力:

1
2
3
public interface BeanNameAware extends Aware {
void setBeanName(String name);
}

使用方式

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
@SpringBootApplication
public class A14ExtensionPoint {
public static void main(String[] args) {
ConfigurableApplicationContext context =
SpringApplication.run(A14ExtensionPoint.class);
MyBean myBean = context.getBean(MyBean.class);
Assert.isTrue(BEAN_NAME.equals(myBean.beanName), "Bean 的 name 不相等");
context.close();
}

private static final String BEAN_NAME = "A Yi A Yi A";

static class MyBean implements BeanNameAware {

private String beanName;

@Override
public void setBeanName(String name) {
this.beanName = name;
}
}

@Configuration
static class MyConfig {
@Bean(BEAN_NAME)
public MyBean myBean() {
return new MyBean();
}
}
}

执行

它将在 Bean 初始化之前被执行,在 AbstractAutowireCapableBeanFactory#initializeBean() 方法的首行调用了 invokeAwareMethods() 方法,此方法完成了 BeanNameAware 等多个 Aware 的执行:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
private void invokeAwareMethods(String beanName, Object bean) {
if (bean instanceof Aware) {
if (bean instanceof BeanNameAware beanNameAware) {
beanNameAware.setBeanName(beanName);
}
if (bean instanceof BeanClassLoaderAware beanClassLoaderAware) {
ClassLoader bcl = getBeanClassLoader();
if (bcl != null) {
beanClassLoaderAware.setBeanClassLoader(bcl);
}
}
if (bean instanceof BeanFactoryAware beanFactoryAware) {
beanFactoryAware.setBeanFactory(AbstractAutowireCapableBeanFactory.this);
}
}
}

至于到 initializeBean() 的具体流程,可以参考前文【Bean 后置处理器】的执行逻辑。

8. @PostConstruct

8.1 拓展点的作用

该注解的全限定类名是 @javax.annotation.PostConstruct,它并非 Spring 提供,但 Spring 为其提供了实现:

1
2
3
4
5
@Documented
@Retention (RUNTIME)
@Target(METHOD)
public @interface PostConstruct {
}

在 JDK8 之前,该注解可以直接使用;JDK9 之后引入模块系统,将该注解剔除了 JDK,因此需要引入额外的依赖:

1
2
3
4
5
<dependency>
<groupId>jakarta.annotation</groupId>
<artifactId>jakarta.annotation-api</artifactId>
<version>2.1.1</version>
</dependency>

@PostConstruct 只能作用于方法上, 在依赖注入完成后,执行一次被 @PostConstruct 注解标记的方法。

在一个类中,被 @PostConstruct 注解标记的方法只能有一个。

@PostConstruct 注解标记的方法必须满足以下条件:

  • 该方法不能有任何参数,除非是拦截器,在这种情况下,需要一个由拦截器规范定义的 InvocationContext 对象;

  • 在拦截器类或拦截器类的超类上定义的方法必须具有以下签名之一:

    1
    2
    void <METHOD>(InvocationContext)
    Object <METHOD>(InvocationContext) throws Exception

    注意:@PostConstruct 标记的拦截方法不得抛出应用程序异常,但如果在同一个拦截方法中除了生命周期事件外还对业务或超时方法进行了拦截,则可以通过 throws 抛出包括 java.lang.Exception 在内的受检异常。如果 @PostConstruct 标记的拦截方法有返回值,容器会忽略该值;

  • 在非拦截器类上定义的方法必须具有以下签名:

    1
    void <METHOD>()
  • @PostConstruct 注解标记的方法可以是 publicprotectedpackage privateprivate

  • 除应用程序客户端外,该方法不能是静态方法;

  • 该方法不能是 final 的;

  • 如果该方法抛出一个非受检异常,则该类不会投入使用,除非该异常被拦截器处理。

8.2 使用方式

比如存在 A07Example 类,将其交由 Spring 管理,内部依赖了 A07Dependence 类型的 Bean:

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
private static final String BEAN_NAME = "a07Example";

@Component
static class A07Dependence {
public A07Dependence() {
System.out.println("1. 执行了 A07Dependence 的无参构造");
}
}

@Component(BEAN_NAME)
static class A07Example {
private A07Dependence dependence;

public A07Example(A07Dependence dependence) {
System.out.println("2. 执行了 A07Example 的无参构造");
}

@Autowired
public void setDependence(A07Dependence dependence) {
this.dependence = dependence;
System.out.println("3. A07Example 注入 dependence");
}

@PostConstruct
public void init() {
System.out.println("5. 执行了 @PostConstruct 标记的方法");
}
}

再提供一个 BeanPostProcessor 的实现类,用于确定被 @PostConstruct 注解标记的方法是什么时候执行的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Component
static class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (BEAN_NAME.equals(beanName)) {
System.out.println("4. 执行了 postProcessBeforeInitialization 方法");
}
return bean;
}

@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (BEAN_NAME.equals(beanName)) {
System.out.println("6. 执行了 postProcessAfterInitialization 方法");
}
return bean;
}
}
1
2
3
4
5
6
7
@SpringBootApplication
public class A08ExtensionPoint {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(A08ExtensionPoint.class, args);
context.close();
}
}
1. 执行了 A07Dependence 的无参构造
2. 执行了 A07Example 的无参构造
3. A07Example 注入 dependence
4. 执行了 postProcessBeforeInitialization 方法
5. 执行了 @PostConstruct 标记的方法
6. 执行了 postProcessAfterInitialization 方法

A07Example 还实现了 InitializingBean 接口,这会在下一节讲到。

可以看到,被 @PostConstruct 标记的方法会在依赖注入后、postProcessBeforeInitialization() 方法后、postProcessAfterInitialization() 方法前执行。

8.3 执行

@PostConstruct 标记的方法是什么时候执行的呢?

前文的使用示例可以确定大致范围,如果需要确定准确的时间点,最好的方式还是在被 @PostConstruct 标记的方法里打一个断点,通过方法调用栈进行追踪:

断点被@PostConstruct标记的方法的调用栈

在调用栈中可以看到熟悉的 AbstractAutowireCapableBeanFactory#doCreateBean() 方法,最终来到 AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsBeforeInitialization() 方法中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Override
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean,
String beanName)
throws BeansException {

Object result = existingBean;
for (BeanPostProcessor processor : getBeanPostProcessors()) {
Object current = processor.postProcessBeforeInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}

这个方法很熟悉,在前文介绍 BeanPostProcessor 中方法的执行时机时进行了讲解,难道说 @PostConstruct 注解会由 BeanPostProcessor 的一个实现类进行解析?

定位到那一步,查看遍历的 processor 是何许人也:

使用CommonAnnotationBeanPostProcessor解析@PostConstruct注解

引出了一个新类:CommonAnnotationBeanPostProcessor

CommonAnnotationBeanPostProcessor的类图

CommonAnnotationBeanPostProcessor 并未直接实现 BeanPostProcessor 接口,而是继承了 InitDestroyAnnotationBeanPostProcessor,后者实现了 BeanPostProcessor 的子接口,重写的 postProcessBeforeInitialization() 方法也在这个类中:

1
2
3
4
5
6
7
8
9
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
LifecycleMetadata metadata = findLifecycleMetadata(bean.getClass());
try {
metadata.invokeInitMethods(bean, beanName);
}
// catch 异常并处理
return bean;
}

一共就两部:

  1. 先找到生命周期元数据,即:LifecycleMetadata
  2. 然后根据 LifecycleMetadata 执行初始化方法。

InitDestroyAnnotationBeanPostProcessor#findLifecycleMetadata()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
private LifecycleMetadata findLifecycleMetadata(Class<?> beanClass) {
if (this.lifecycleMetadataCache == null) {
// Happens after deserialization, during destruction...
return buildLifecycleMetadata(beanClass);
}
// Quick check on the concurrent map first, with minimal locking.
LifecycleMetadata metadata = this.lifecycleMetadataCache.get(beanClass);
if (metadata == null) {
synchronized (this.lifecycleMetadataCache) {
metadata = this.lifecycleMetadataCache.get(beanClass);
if (metadata == null) {
metadata = buildLifecycleMetadata(beanClass);
this.lifecycleMetadataCache.put(beanClass, metadata);
}
return metadata;
}
}
return metadata;
}

重点是其中的 buildLifecycleMetadata() 方法:

1
2
3
4
5
6
7
8
9
private LifecycleMetadata buildLifecycleMetadata(final Class<?> beanClass) {
if (!AnnotationUtils.isCandidateClass(beanClass, this.initAnnotationTypes) &&
!AnnotationUtils.isCandidateClass(beanClass, this.destroyAnnotationTypes)) {
return this.emptyLifecycleMetadata;
}

// 后续无非是通过反射获取 beanClass 中的所有方法,
// 收集目标方法后包装成 LifecycleMetadata,然后返回
}

重点是 AnnotationUtils.isCandidateClass() 方法,这里调用了两次,如果都返回 false 则直接返回 emptyLifecycleMetadata

除此之外,initAnnotationTypesdestroyAnnotationTypes 应该是目标注解类型,那它们的值是什么呢?

1
2
3
private final Set<Class<? extends Annotation>> initAnnotationTypes = new LinkedHashSet<>(2);

private final Set<Class<? extends Annotation>> destroyAnnotationTypes = new LinkedHashSet<>(2);

initAnnotationTypes 为例,提供了 addInitAnnotationType() 方法:

1
2
3
4
5
public void addInitAnnotationType(@Nullable Class<? extends Annotation> initAnnotationType) {
if (initAnnotationType != null) {
this.initAnnotationTypes.add(initAnnotationType);
}
}

该方法在 CommonAnnotationBeanPostProcessor 的构造函数中被调用,利用 loadAnnotationType() 加载指定全限定类名的注解:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public CommonAnnotationBeanPostProcessor() {
setOrder(Ordered.LOWEST_PRECEDENCE - 3);

// Jakarta EE 9 set of annotations in jakarta.annotation package
addInitAnnotationType(loadAnnotationType("jakarta.annotation.PostConstruct"));
addDestroyAnnotationType(loadAnnotationType("jakarta.annotation.PreDestroy"));

// Tolerate legacy JSR-250 annotations in javax.annotation package
addInitAnnotationType(loadAnnotationType("javax.annotation.PostConstruct"));
addDestroyAnnotationType(loadAnnotationType("javax.annotation.PreDestroy"));

// java.naming module present on JDK 9+?
if (jndiPresent) {
this.jndiFactory = new SimpleJndiBeanFactory();
}
}

至于 loadAnnotationType() 的实现逻辑,无非是对 Class.forName() 的包装,这不是重点。

再回到 AnnotationUtils.isCandidateClass() 方法:

1
2
3
4
5
6
7
8
public static boolean isCandidateClass(Class<?> clazz, Collection<Class<? extends Annotation>> annotationTypes) {
for (Class<? extends Annotation> annotationType : annotationTypes) {
if (isCandidateClass(clazz, annotationType)) {
return true;
}
}
return false;
}

内部调用了 isCandidateClass() 方法:

1
2
3
public static boolean isCandidateClass(Class<?> clazz, @Nullable Class<? extends Annotation> annotationType) {
return (annotationType != null && isCandidateClass(clazz, annotationType.getName()));
}

又调用重载的 isCandidateClass() 方法:

1
2
3
4
5
6
7
8
9
10
public static boolean isCandidateClass(Class<?> clazz, String annotationName) {
// 注解以 `java.` 开头,直接返回 true
if (annotationName.startsWith("java.")) {
return true;
}
if (AnnotationsScanner.hasPlainJavaAnnotationsOnly(clazz)) {
return false;
}
return true;
}

最后调用了 AnnotationsScanner.hasPlainJavaAnnotationsOnly() 方法,如果它返回 true,最终返回 false,否则最终返回 true

1
2
3
4
static boolean hasPlainJavaAnnotationsOnly(Class<?> type) {
// 如果目标类的全限定类名以 `java.` 开头,或者是 Ordered 的子类,就返回 true
return (type.getName().startsWith("java.") || type == Ordered.class);
}

分析了半天,好像并没有什么有意思的东西… 😅

InitDestroyAnnotationBeanPostProcessor.LifecycleMetadata#invokeInitMethods()

回到 invokeInitMethods() 方法,看看是怎么执行目标方法的,多半是遍历每个目标方法然后利用反射去执行:

1
2
3
4
5
6
7
8
9
10
11
12
13
public void invokeInitMethods(Object target, String beanName) throws Throwable {
Collection<LifecycleMethod> checkedInitMethods = this.checkedInitMethods;
Collection<LifecycleMethod> initMethodsToIterate =
(checkedInitMethods != null ? checkedInitMethods : this.initMethods);
if (!initMethodsToIterate.isEmpty()) {
for (LifecycleMethod lifecycleMethod : initMethodsToIterate) {
if (logger.isTraceEnabled()) {
logger.trace("Invoking init method on bean '" + beanName + "': " + lifecycleMethod.getMethod());
}
lifecycleMethod.invoke(target);
}
}
}

又是遍历,然后执行了 InitDestroyAnnotationBeanPostProcessor.LifecycleMethod#invoke() 方法:

1
2
3
4
public void invoke(Object target) throws Throwable {
ReflectionUtils.makeAccessible(this.method);
this.method.invoke(target);
}

果不其然,印证了前面的猜想。

总结

执行逻辑很简单,概括后就两步:

  1. 遍历目标类中的每个方法,收集被指定注解标记的方法;
  2. 反射执行被指定注解标记的方法

9. 初始化 Bean

9.1 拓展点的作用

初始化 Bean,即:InitializingBean,它并非 SpringBoot 提供,是在 Spring 中就存在的:

1
2
3
4
5
6
7
8
public interface InitializingBean {

/**
* 属性注入后执行
*/
void afterPropertiesSet() throws Exception;

}

其中仅有一个无参无返回值的 afterPropertiesSet(),根据方法名称可知,这个方法很有可能在属性注入后执行。

9.2 使用方式

实现 InitializingBean 接口并重写 afterPropertiesSet() 方法,将实现类交由 Spring 管理,并且在类中使用 @PostConstruct 注解标记:

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
private static final String EXAMPLE_BEAN_NAME = "a08-example";

@Component
static class A08Dependence {
}

static class A08Example implements InitializingBean {
private A08Dependence dependence;

@Autowired
public void setDependence(A08Dependence dependence) {
this.dependence = dependence;
System.out.println("1. A08Example 注入 dependence");
}

@Override
public void afterPropertiesSet() throws Exception {
System.out.println("4. 执行了 afterPropertiesSet 方法");
}

@PostConstruct
public void init() {
System.out.println("3. 执行了 init 方法");
}

public void initMethod() {
System.out.println("5. 执行了 init-method");
}
}

@Configuration
static class MyConfig {
@Bean(value = EXAMPLE_BEAN_NAME, initMethod = "initMethod")
public A08Example a08Example() {
return new A08Example();
}
}

同样提供一个 BeanPostProcessor 的实现类,用于确定 afterPropertiesSet() 方法是什么时候执行的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Component
static class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (EXAMPLE_BEAN_NAME.equals(beanName)) {
System.out.println("2. 执行了 postProcessBeforeInitialization 方法");
}
return bean;
}

@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (EXAMPLE_BEAN_NAME.equals(beanName)) {
System.out.println("5. 执行了 postProcessAfterInitialization 方法");
}
return bean;
}
}
1
2
3
4
5
6
7
@SpringBootApplication
public class A09ExtensionPoint {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(A09ExtensionPoint.class, args);
context.close();
}
}
1. A08Example 注入 dependence
2. 执行了 postProcessBeforeInitialization 方法
3. 执行了 init 方法
4. 执行了 afterPropertiesSet 方法
5. 执行了 init-method
6. 执行了 postProcessAfterInitialization 方法

可以看到,afterPropertiesSet() 方法在 postProcessAfterInitialization() 方法前执行,同时还在 init-method 方法前执行。

9.3 执行

前文的使用示例可以确定大致范围,要确定准确的范围也可以利用断点查看方法调用栈:

断点afterPropertiesSet方法的调用栈

又见熟悉的 doCreateBean() 方法,之后进入 initializeBean() 方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
invokeAwareMethods(beanName, bean);

Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}

try {
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null), beanName, ex.getMessage(), ex);
}
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}

return wrappedBean;
}

而后调用 invokeInitMethods() 方法,根据调用方法栈可知,在调用 invokeInitMethods() 方法后,就执行了重写的 afterPropertiesSet() 方法:

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
protected void invokeInitMethods(String beanName, 
Object bean,
@Nullable RootBeanDefinition mbd) throws Throwable {
// 如果当前的 Bean 也是 InitializingBean 实例
boolean isInitializingBean = (bean instanceof InitializingBean);
if (isInitializingBean &&
// 不含名为 afterPropertiesSet 的外部管理初始方法
(mbd == null || !mbd.hasAnyExternallyManagedInitMethod("afterPropertiesSet"))) {
// 省略打印日志
// 执行 afterPropertiesSet 方法
((InitializingBean) bean).afterPropertiesSet();
}

if (mbd != null && bean.getClass() != NullBean.class) {
// 获取所有初始方法名
String[] initMethodNames = mbd.getInitMethodNames();
if (initMethodNames != null) {
// 遍历初始化方法名
for (String initMethodName : initMethodNames) {
if (StringUtils.hasLength(initMethodName) &&
!(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
!mbd.hasAnyExternallyManagedInitMethod(initMethodName)) {
// 利用反射执行自定义初始方法
invokeCustomInitMethod(beanName, bean, mbd, initMethodName);
}
}
}
}
}

在第一个 if 判断中执行了 InitializingBeanafterPropertiesSet() 方法。

如果对使用示例的 initMethod() 方法进行断点,则会进入第二个 if 分支,在内部调用 invokeCustomInitMethod() 方法利用反射执行 initMethod() 方法。

9.4 内置实现

利用 InitializingBean 接口可以修改默认设置的属性值、添加额外的属性值,或者对某些属性值进行校验,在 Spring MVC 中有个名为 RequestMappingHandlerMapping 的类,用于实现 Controller 与 URL 的映射。它也实现了 InitializingBean 接口:

RequestMappingHandlerMapping的类图

10. 智能初始化单例

10.1 拓展点的作用

智能初始化单例,即:SmartInitializingSingleton,它并非 SpringBoot 提供,是在 Spring 中就存在的:

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

/**
* 在单例 Bean 预实例化阶段结束后调用,保证已经创建了所有常规的单例 Bean。
* 在此方法中调用 `ListableBeanFactory.getBeansOfType()` 方法不会在启动过程中
* 触发意外的副作用。
* 注意:对于懒加载的单例 Bean 和多例 Bean,在 BeanFactory 启动后,不会触发
* 此回调。请谨慎使用,仅用于具有预期启动含义的 Bean。
*/
void afterSingletonsInstantiated();

}

其中仅有一个无参无返回值的 afterSingletonsInstantiated(),根据方法名称可知,这个方法很有可能在 Bean 初始化后执行。

注意: 是在所有单例 Bean 初始化完成后执行,对懒加载单例 Bean 和多例 Bean 则没要求。

10.2 使用方式

实现 SmartInitializingSingleton 接口,重写 afterSingletonsInstantiated() 方法,并将实现类交由 Spring 管理:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
private static final String BEAN_NAME = "myBean";

@Component(BEAN_NAME)
static class MySmartInitializingSingleton implements InitializingBean, SmartInitializingSingleton {
@Override
public void afterPropertiesSet() {
System.out.println("1. 执行了 afterPropertiesSet 方法");
}

@Override
public void afterSingletonsInstantiated() {
System.out.println("3. 执行了 afterSingletonsInstantiated 方法");
}
}

同样提供一个 BeanPostProcessor 的实现类,只重写 postProcessAfterInitialization() 方法,用于确定 afterSingletonsInstantiated() 方法是什么时候执行的:

1
2
3
4
5
6
7
8
9
10
@Component
static class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (BEAN_NAME.equals(beanName)) {
System.out.println("2. 执行了 postProcessAfterInitialization 方法");
}
return bean;
}
}
1
2
3
4
5
6
7
@SpringBootApplication
public class A10ExtensionPoint {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(A10ExtensionPoint.class, args);
context.close();
}
}
1. 执行了 afterPropertiesSet 方法
2. 执行了 postProcessAfterInitialization 方法
3. 执行了 afterSingletonsInstantiated 方法

可以看到,afterSingletonsInstantiated() 会在 postProcessAfterInitialization() 方法后执行,确实是在 Bean 初始化完成后执行。

10.3 执行

至于执行时机,其实在【4.3 注册与执行】中介绍 BeanPostProcessor 的执行时机时已经介绍过。

目前已知的情报是会在单例 Bean 初始化完成后执行 afterSingletonsInstantiated() 方法。

AbstractApplicationContext#refresh() 方法为入口:

flowchart TD
1("AbstractApplicationContext#refresh()")
2("AbstractApplicationContext#finishBeanFactoryInitialization()")
3("DefaultListableBeanFactory#preInstantiateSingletons()")
1 --> 2 --> 3

preInstantiateSingletons() 方法中有:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Override
public void preInstantiateSingletons() throws BeansException {
// --snip--

// Trigger initialization of all non-lazy singleton beans...
// 触发所有非懒加载单例 Bean 的初始化

// Trigger post-initialization callback for all applicable beans...
for (String beanName : beanNames) {
Object singletonInstance = getSingleton(beanName);
if (singletonInstance instanceof SmartInitializingSingleton smartSingleton) {
StartupStep smartInitialize = getApplicationStartup().start("spring.beans.smart-initialize")
.tag("beanName", beanName);
// 执行 afterSingletonsInstantiated() 方法
smartSingleton.afterSingletonsInstantiated();
smartInitialize.end();
}
}
}

执行过程很简单,几步就走到了 afterSingletonsInstantiated() 的执行点。

11. 两个执行器

11.1 拓展点的作用

本节拓展点的名字并不是真的叫“两个执行器”,😂 而是将在本节介绍两个拓展点,它们以 Runner 结尾,翻译成执行器也没啥问题。

这两个执行器分别是 CommandLineRunnerApplicationRunner

为什么要在本节一起介绍,是因为它们很类似,执行时间点也很靠近,它们都拥有名为 run() 的方法,只是参数不同:

1
2
3
4
5
6
7
8
9
@FunctionalInterface
public interface CommandLineRunner {
void run(String... args) throws Exception;
}

@FunctionalInterface
public interface ApplicationRunner {
void run(ApplicationArguments args) throws Exception;
}

前面介绍的拓展点都是在 Spring 中本身就存在的,而不是 SpringBoot 单独提供的,而本节的这两个执行器则是由 SpringBoot 提供。

ApplicationRunner 会早于 CommandLineRunner 执行,它们都将在 Spring 容器、Web 容器启动后,正式处理业务请求前(即项目启动的最后一步)执行。

这两个接口可用于正式处理业务请求前预加载热点数据、清除临时文件、读取自定义配置信息等。

在一个应用程序上下文中可以定义多个 ApplicationRunnerCommandLineRunner,此时可以使用 Ordered 接口或 @Order 注解对这些执行器的执行顺序进行排序。

11.2 使用方式

分别实现 ApplicationRunnerCommandLineRunner 接口,重写其中的 run() 方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
private static final String COMMAND_LINE_BEAN = "command-line-bean";
private static final String APPLICATION_BEAN = "application-bean";

@Component(COMMAND_LINE_BEAN)
static class MyCommandLineRunner implements CommandLineRunner {
@Override
public void run(String... args) throws Exception {
System.out.println("执行 CommandLineRunner");
}
}

@Component(APPLICATION_BEAN)
static class MyApplicationRunner implements ApplicationRunner {
@Override
public void run(ApplicationArguments args) throws Exception {
System.out.println("执行 ApplicationRunner");
}
}

再次提供一个 BeanPostProcessor 的实现类,只重写 postProcessAfterInitialization() 方法:

1
2
3
4
5
6
7
8
9
10
11
12
private static final Set<String> BEAN_NAMES = Set.of(COMMAND_LINE_BEAN, APPLICATION_BEAN);

@Component
static class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (BEAN_NAMES.contains(beanName)) {
System.out.printf("检测到指定 Bean:[%s] 的 postProcessAfterInitialization 方法%n", beanName);
}
return bean;
}
}
1
2
3
4
5
6
7
@SpringBootApplication
public class A11ExtensionPoint {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(A11ExtensionPoint.class);
context.close();
}
}
检测到指定 Bean:[application-bean] 的 postProcessAfterInitialization 方法
检测到指定 Bean:[command-line-bean] 的 postProcessAfterInitialization 方法
执行 ApplicationRunner
执行 CommandLineRunner

根据使用示例可知 ApplicationRunner 确实会早于 CommandLineRunner 执行。

11.3 执行

前文中许多拓展点都与 refresh() 方法有关,refresh 一词可译为“刷新”,表示刷新上下文,其中最重要的就是将 Bean 添加到 Spring 容器(Spring 容器是 Spring 上下文的一部分)中。从使用示例可知,本节的两个拓展点会在 Bean 初始化之后执行,那么很有可能不会在 refresh() 方法中执行。

从 Spring 主启动类出发:

flowchart TD
1("SpringApplication#run(java.lang.Class<?>, java.lang.String...)")
2("SpringApplication#run(java.lang.Class<?>[], java.lang.String[])")
3("SpringApplication#run(java.lang.String...)")

1 --> 2 --> 3

执行时机既不在 refreshContext() 中,也不在 afterRefresh() 中,而是在最后的 callRunners() 中,这方法名称也很明确——调用执行器:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
private void callRunners(ApplicationContext context, ApplicationArguments args) {
List<Object> runners = new ArrayList<>();
// 从容器中获取两种执行器
runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
// 对他们排个序
AnnotationAwareOrderComparator.sort(runners);
// 遍历并一一执行
for (Object runner : new LinkedHashSet<>(runners)) {
if (runner instanceof ApplicationRunner applicationRunner) {
callRunner(applicationRunner, args);
}
if (runner instanceof CommandLineRunner commandLineRunner) {
callRunner(commandLineRunner, args);
}
}
}

12. 工厂 Bean

12.1 拓展点的作用

工厂 Bean,即:FactoryBean,它并非 SpringBoot 提供,是在 Spring 中就存在的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public interface FactoryBean<T> {

String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";

@Nullable
T getObject() throws Exception;

@Nullable
Class<?> getObjectType();

default boolean isSingleton() {
return true;
}

}

FactoryBean 其实并不能认为是拓展点,它是创建复杂 Bean 的一种方式。

在 Spring 中有一个类似的接口,名为 BeanFactory,有一道常见的面试题:BeanFactoryFactoryBean 有什么异同?

它们之间的异倒是很大,至于同就只有名字长得比较相似了。BeanFactory 译为“Bean 工厂”,即生产存储 Bean 的地方,也就是常说的 Spring 容器;FactoryBean 译为“工厂 Bean”,是创建 Bean 的一种方式,就像设计模式中的工厂模式一样。

FactoryBean 中有三个方法:

  • getObject():获取 Bean 对象,用于创建一些难以使用常规方式创建的 Bean;
  • getObjectType():用于获取返回 Bean 的类型;
  • isSingleton():创建的 Bean 是否是单例 Bean,默认 true

12.2 使用方式

假设存在名为 Owl 的“复杂类”,尽管并不复杂:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
static class Owl {
@Getter
@Setter
private String name;

public Owl() {
System.out.println("执行了无参构造");
}

public Owl(String name) {
this.name = name;
System.out.println("执行了有参(name)构造");
}
}

编写 FactoryBean 的实现类,重写其中的抽象方法,其中的 getObject() 方法返回 Owl 实例,并将实现类交由 Spring 管理:

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
private static final String OWL_BEAN_NAME = "owl";

@Component(OWL_BEAN_NAME)
static class OwlFactoryBean implements FactoryBean<Owl> {

public OwlFactoryBean() {
System.out.println("执行了 OwlFactoryBean 的无参构造");
}

@Override
public Owl getObject() throws Exception {
System.out.println("执行 getObject--start");
Owl owl = new Owl();
System.out.println("执行 getObject--end");
return owl;
}

@Override
public Class<?> getObjectType() {
return Owl.class;
}

@Override
public boolean isSingleton() {
return true;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
@SpringBootApplication
public class A12ExtensionPoint {
public static void main(String[] args) {
ConfigurableApplicationContext context =
SpringApplication.run(A12ExtensionPoint.class);
// 通过 bean 的 name 获取
Object bean = context.getBean(OWL_BEAN_NAME);
Assert.isInstanceOf(Owl.class, bean);
bean = context.getBean(BeanFactory.FACTORY_BEAN_PREFIX + OWL_BEAN_NAME);
Assert.isInstanceOf(OwlFactoryBean.class, bean);
context.close();
}
}
执行了 OwlFactoryBean 的无参构造
执行 getObject--start
执行了无参构造
执行 getObject--end

从容器中按照名称获取与 OwlFactoryBean 同名的 Bean 时,得到的 Bean 的类型并不是 OwlFactoryBean,而是 Owl 类型的,如果要获取原始类型,则需要在名称前添加 &(有点 C 语言的味道)。

12.3 注册

在注册 FactoryBean 类型的 Bean 时,按照给定的 Bean 名称或者默认规则进行注册,在 Spring 容器中只会存在 FactoryBean 类型的 Bean,不会存在 getObjectType() 返回的类型、 getObject() 返回的对象的 Bean。

通过 getBean() 方法按照注册的 FactoryBean 类型的 Bean 的名称在 Spring 容器中获取 Bean 时,获取到的是 getObject() 返回的对象,能够获取到这样的对象是 getBean() 方法中的细节,而不是在 Spring 容器中真实存在的。

12.4 执行

名称的细微差别能够通过 getBean() 方法获取到不同的 Bean 对象,那么就看看 getBean() 中的细节吧。

flowchart TD
1("AbstractBeanFactory#getBean(java.lang.String)")
2("AbstractBeanFactory#doGetBean()")

1 --> 2

来到 doGetBean() 方法后,不会像前文分析的那样来到 createBean() 方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
protected <T> T doGetBean(
String name, @Nullable Class<T> requiredType,
@Nullable Object[] args, boolean typeCheckOnly) throws BeansException {

String beanName = transformedBeanName(name);
Object beanInstance;

// Eagerly check singleton cache for manually registered singletons.
// 检查单例缓存总是否有手动创建的单例 Bean
// 以 owl 为例,获取到的是 FactoryBean 对象
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
// 打印了些日志

// 获取给定 Bean 实例的对象,可以是 Bean 实例本身,也可以是 FactoryBean 创建的对象
beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null);
} else {
// --snip--
}
}

而是会进入 getObjectForBeanInstance() 方法:

1
2
3
4
5
6
7
8
9
10
11
@Override
protected Object getObjectForBeanInstance(
Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {

String currentlyCreatedBean = this.currentlyCreatedBean.get();
if (currentlyCreatedBean != null) {
registerDependentBean(beanName, currentlyCreatedBean);
}

return super.getObjectForBeanInstance(beanInstance, name, beanName, mbd);
}

然后调用父类的 getObjectForBeanInstance() 方法:

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
protected Object getObjectForBeanInstance(
Object beanInstance, String name,
String beanName, @Nullable RootBeanDefinition mbd) {

// Don't let calling code try to dereference the factory if the bean isn't a factory.
// 如果 bean 不是工厂,则不要让调用代码尝试取消引用工厂

// 如果 name 以 & 开头
if (BeanFactoryUtils.isFactoryDereference(name)) {
if (beanInstance instanceof NullBean) {
return beanInstance;
}
if (!(beanInstance instanceof FactoryBean)) {
throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());
}
if (mbd != null) {
mbd.isFactoryBean = true;
}
// 如果 name 以 & 开头,直接返回 FactoryBean 对象
return beanInstance;
}

// Now we have the bean instance, which may be a normal bean or a FactoryBean.
// If it's a FactoryBean, we use it to create a bean instance, unless the
// caller actually wants a reference to the factory.
// 现在我们已经有了 Bean 实例,它可能是一个普通的 Bean 或 FactoryBean
// 如果是 FactoryBean,就用它创建一个 Bean 实例,除非调用者实际想要的是工厂的引用
if (!(beanInstance instanceof FactoryBean<?> factoryBean)) {
// 获取到的 Bean 实例不是 FactoryBean 类型,name 也不以 & 开头
// 证明是普通 Bean,那么返回即可
return beanInstance;
}

Object object = null;
if (mbd != null) {
mbd.isFactoryBean = true;
}
else {
// 从缓存中获取 Bean
object = getCachedObjectForFactoryBean(beanName);
}
if (object == null) {
// Return bean instance from factory.
// 从 factory 中返回 bean 实例
// Caches object obtained from FactoryBean if it is a singleton.
// 如果 FactoryBean 是单例,则缓存从 FactoryBean 获取的对象
if (mbd == null && containsBeanDefinition(beanName)) {
mbd = getMergedLocalBeanDefinition(beanName);
}
boolean synthetic = (mbd != null && mbd.isSynthetic());
// 从 FactoryBean 中获取 Bean
object = getObjectFromFactoryBean(factoryBean, beanName, !synthetic);
}
return object;
}

然后调用 getObjectFromFactoryBean() 方法:

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
protected Object getObjectFromFactoryBean(FactoryBean<?> factory, 
String beanName, boolean shouldPostProcess) {
// FactoryBean 返回的 Bean 是单例的,beanName 在 singletonObjects 中存在
if (factory.isSingleton() && containsSingleton(beanName)) {
// 锁住 singletonObjects
synchronized (getSingletonMutex()) {
// 从缓存中获取
Object object = this.factoryBeanObjectCache.get(beanName);
if (object == null) {
// 获取不到,直接通过 factory 的 getObject() 方法获取对象
object = doGetObjectFromFactoryBean(factory, beanName);
// Only post-process and store if not put there already during getObject() call above
// (e.g. because of circular reference processing triggered by custom getBean calls)
// 如果在上面的 getObject() 调用期间还没有放在那里,则只进行后期处理和存储
// (例如,因为自定义getBean调用触发了循环引用处理)
Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
if (alreadyThere != null) {
object = alreadyThere;
}
else {
// BeanDefinition 不是合成的,就要进行后置处理
if (shouldPostProcess) {
// 获取的单例是否正在创建
if (isSingletonCurrentlyInCreation(beanName)) {
// Temporarily return non-post-processed object, not storing it yet..
// 暂时返回未经后处理的对象,暂不存储
return object;
}
beforeSingletonCreation(beanName);
try {
// 后置处理 Bean
// 调用 BeanPostProcessor 的 postProcessAfterInitialization()
object = postProcessObjectFromFactoryBean(object, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName,
"Post-processing of FactoryBean's singleton object failed", ex);
}
finally {
afterSingletonCreation(beanName);
}
}
// 给定的 beanName 在 singletonObjects 中存在
if (containsSingleton(beanName)) {
// 更新 factoryBeanObjectCache,下次就不用再次获取,直接从缓存中拿
// 这样的话能够保证始终获取到的是同一个对象
this.factoryBeanObjectCache.put(beanName, object);
}
}
}
return object;
}
}
// 不是单例,或者 beanName 在 singletonObjects 中不存在
else {
// 再次调用 FactoryBean 的 getObject() 获取 Bean
Object object = doGetObjectFromFactoryBean(factory, beanName);
if (shouldPostProcess) {
try {
// 同样进行后置处理
object = postProcessObjectFromFactoryBean(object, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
}
}
return object;
}
}

概括一下:

  • 如果是单例的,先尝试从 factoryBeanObjectCache 中获取,保证每次获取到的都是同一个对象;如果在缓存中不存在,那么调用 getObject() 方法拿到 Bean,并进行后置处理,最后存储到 factoryBeanObjectCache 中;
  • 如果不是单例、或者在 beanNamesingletonObjects 中不存在,每次调用 getObject() 方法拿到新的 Bean,同样进行后置处理。

13. 废弃 Bean

13.1 拓展点的作用

废弃 Bean,即:DisposableBean,它并非 SpringBoot 提供,是在 Spring 中就存在的:

1
2
3
public interface DisposableBean {
void destroy() throws Exception;
}

接口内部只有一个无参无返回值的 destroy() 方法,为 Spring Bean 提供了一种释放资源的方式,能够在 Spring 容器关闭,销毁所有 Bean 时回调。

DisposableBean 接口与 InitializingBean 接口有些类似,但触发时机不同。

13.2 使用方式

实现 DisposableBean 接口并重写 destroy() 方法,将实现类交由 Spring 管理,还提供 ApplicationRunner 的实现类,作为对比:

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
@Component
static class MyRunner implements ApplicationRunner {
@Override
public void run(ApplicationArguments args) throws Exception {
System.out.printf("1. [%s]: 执行了 ApplicationRunner 方法\n", getCurrentThreadName());
}
}

static class A13DisposableBean implements DisposableBean {

@Override
public void destroy() {
System.out.printf("4. [%s]: 执行了 destroy 方法\n", getCurrentThreadName());
}

@PreDestroy
public void preDestroy() {
System.out.printf("3. [%s]: 执行了 @preDestroy 方法\n", getCurrentThreadName());
}

public void destroyMethod() {
System.out.printf("5. [%s]: 执行了 destroy-method\n", getCurrentThreadName());
}
}

@Configuration
static class MyConfig {
@Bean(destroyMethod = "destroyMethod")
public A13DisposableBean a13DisposableBean() {
return new A13DisposableBean();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@SpringBootApplication
public class A13ExtensionPoint {
@SneakyThrows
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(A13ExtensionPoint.class);
System.out.printf("2. [%s]: main 方法执行完毕,准备关闭容器\n", getCurrentThreadName());
TimeUnit.SECONDS.sleep(1);
context.close();
/*
* 可以不直接关闭容器,而是通过 `System.exit(0)` 关闭,此时会触发 shutdown hooks;
* 或者是在 IDEA 中,手动停止程序,也会触发 shutdown hooks
*/
}

public static String getCurrentThreadName() {
return Thread.currentThread().getName();
}
}
1. [main]: 执行了 ApplicationRunner 方法
2. [main]: main 方法执行完毕,准备关闭容器
3. [main]: 执行了 @preDestroy 方法
4. [main]: 执行了 destroy 方法
5. [main]: 执行了 destroy-method

对于 Bean 的初始化来说,有三个类似的拓展点,并 按顺序依次执行:

  • @PostConstruct
  • InitializingBean#afterPropertiesSet()
  • @Bean 注解的 initMethod 属性

而对于 Bean 的销毁来说,也有三个类似的拓展点,也 按顺序依次执行:

  • @PreDestroy
  • DisposableBean#destroy()
  • @Bean 注解的 destroyMethod 属性

调用的线程

destroy() 方法会在 main 线程中被调用。

如果去掉 context.close() 方法,而是手动或者通过 System.exit(0); 关闭程序,销毁方法们 则会在 SpringApplicationShutdownHook 线程中被调用。在这种情况下,运用了多线程技术,异步执行销毁方法,这涉及到 SpringBoot Shutdown Hook,后续另开一文详细分析, 本节依旧以 context.close() 方法为入口进行探索。

13.3 执行

context.close() 方法为入口,来到 AbstractApplicationContext#close()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Override
public void close() {
synchronized (this.startupShutdownMonitor) {
doClose();
// If we registered a JVM shutdown hook, we don't need it anymore now:
// We've already explicitly closed the context.
if (this.shutdownHook != null) {
try {
Runtime.getRuntime().removeShutdownHook(this.shutdownHook);
}
catch (IllegalStateException ex) {
// ignore - VM is already shutting down
}
}
}
}

重点在 doClose()

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
protected void doClose() {
// Check whether an actual close attempt is necessary...
// 检查是否有必要进行实际的关闭尝试
if (this.active.get() && this.closed.compareAndSet(false, true)) {
if (logger.isDebugEnabled()) {
logger.debug("Closing " + this);
}

try {
// Publish shutdown event.
// 发布 shutdown 事件
publishEvent(new ContextClosedEvent(this));
}
catch (Throwable ex) {
logger.warn("Exception thrown from ApplicationListener handling ContextClosedEvent", ex);
}

// Stop all Lifecycle beans, to avoid delays during individual destruction.
// 停止所有 Lifecycle Bean,以避免在单个销毁过程中出现延迟。
if (this.lifecycleProcessor != null) {
try {
this.lifecycleProcessor.onClose();
}
catch (Throwable ex) {
logger.warn("Exception thrown from LifecycleProcessor on context close", ex);
}
}

// Destroy all cached singletons in the context's BeanFactory.
// 销毁所有在上下文的 BeanFactory 缓存的单例
destroyBeans();

// Close the state of this context itself.
// 关闭上下文本身的状态
closeBeanFactory();

// Let subclasses do some final clean-up if they wish...
// 如果可以,让子类做一些最后的清理
// 比如 ServletWebServerApplicationContext 会实现该勾子函数关闭内嵌的 WebServer(Tomcat)
onClose();

// Reset common introspection caches to avoid class reference leaks.
// 重置常用自省缓存,避免类引用泄漏
resetCommonCaches();

// Reset local application listeners to pre-refresh state.
// 将本地应用程序监听器重置为刷新前状态
if (this.earlyApplicationListeners != null) {
this.applicationListeners.clear();
this.applicationListeners.addAll(this.earlyApplicationListeners);
}

// Switch to inactive.
// 切换到 inactive
this.active.set(false);
}
}

其中的 destroyBeans() 方法用于销毁 Spring 容器中缓存的单例,在这个方法前会执行两件应用关闭前的操作,它们都类似一种通知机制,但在使用场景上也有区别:

  • ContextClosedEvent 是应用级别的事件,监听该事件可以做一些全局性的行为;
  • Lifecycle 是 Bean 级别的通知,更适用于特定 Bean 的行为。

回到 destroyBeans() 方法:

1
2
3
protected void destroyBeans() {
getBeanFactory().destroySingletons();
}

再来到 destroySingletons(),方法有两个实现,主要的实现是 DefaultSingletonBeanRegistry#destroySingletons()

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
public void destroySingletons() {
if (logger.isTraceEnabled()) {
logger.trace("Destroying singletons in " + this);
}
synchronized (this.singletonObjects) {
this.singletonsCurrentlyInDestruction = true;
}

String[] disposableBeanNames;
synchronized (this.disposableBeans) {
// 获取已经缓存的需要被销毁的 Bean 的 name
disposableBeanNames = StringUtils.toStringArray(this.disposableBeans.keySet());
}
for (int i = disposableBeanNames.length - 1; i >= 0; i--) {
// 逆序遍历,一一销毁
destroySingleton(disposableBeanNames[i]);
}

// 清除当前类用到的一些缓存
this.containedBeanMap.clear();
this.dependentBeanMap.clear();
this.dependenciesForBeanMap.clear();

// 清除单例缓存
clearSingletonCache();
}

最后几步清除了当前类中用到的一些缓存包括:

  • containedBeanMap
  • dependentBeanMap
  • dependenciesForBeanMap

插播一下:几个 Map 的含义

对于 dependentBeanMapdependenciesForBeanMap 来说:

1
2
3
4
5
/** Map between dependent bean names: bean name to Set of dependent bean names. */
private final Map<String, Set<String>> dependentBeanMap = new ConcurrentHashMap<>(64);

/** Map between depending bean names: bean name to Set of bean names for the bean's dependencies. */
private final Map<String, Set<String>> dependenciesForBeanMap = new ConcurrentHashMap<>(64);
  • dependentBeanMap:Bean 名称和所有依赖于它的 Bean 的名称的映射关系
  • dependenciesForBeanMap:Bean 名称和它依赖的 Bean 的名称的映射关系
flowchart TD
1("A")
2("B")
3("C")
1 --> 2
1 --> 3

在上图中,A 依赖了 B(A --> B),A 依赖了 C(A --> C),则:

  • dependentBeanMap<B, [A]><C, [A]>
  • dependenciesForBeanMap<A, [B, C]>

至于 containedBeanMap

1
2
/** Map between containing bean names: bean name to Set of bean names that the bean contains. */
private final Map<String, Set<String>> containedBeanMap = new ConcurrentHashMap<>(16);

它表示 Bean 名称与它包含的 Bean 的名称的映射关系。这似乎与 dependenciesForBeanMap 很类似,也确实很类似,但它是在 XML 配置中使用的,在当前流行基于注解的 Spring 配置的环境下,它的使用场景越来越小。比如:

1
2
3
4
5
6
7
8
9
public class Foo {
private Bar bar;
public Foo(Bar bar) {
this.bar = bar;
}
}

public class Bar {
}

Foo 类中依赖了 Bar,那么基于 XML 的配置有:

1
2
3
4
5
<bean id="foo" class="com.example.demo.Foo">
<constructor-arg>
<bean class="com.example.demo.Bar"/>
</constructor-arg>
</bean>

这是不是就相当于 Foo 包含了 Bar?这仅供了解,现在几乎没有使用场景。

再插播下:disposableBeans 的初始化

disposableBeans 的初始化是在熟悉的 doCreateBean() 方法中最后完成:

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
protected Object doCreateBean(String beanName, 
RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {

// Instantiate the bean.
// --snip--

// Allow post-processors to modify the merged bean definition.
// --snip--

// Eagerly cache singletons to be able to resolve circular references
// even when triggered by lifecycle interfaces like BeanFactoryAware.
// --snip--

// Initialize the bean instance.
// --snip--

// Register bean as disposable.
try {
// 在这进行注册,不再深入分析
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
catch (BeanDefinitionValidationException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
}

return exposedObject;
}

回到主线

查看 destroySingleton() 方法,如何根据 Bean 的 name 来进行销毁:

1
2
3
4
5
6
7
8
9
10
11
12
13
public void destroySingleton(String beanName) {
// Remove a registered singleton of the given name, if any.
// 如果有,删除已注册的给定名称的单例 Bean
removeSingleton(beanName);

// Destroy the corresponding DisposableBean instance.
// 销毁相应的 DisposableBean 实例
DisposableBean disposableBean;
synchronized (this.disposableBeans) {
disposableBean = this.disposableBeans.remove(beanName);
}
destroyBean(beanName, disposableBean);
}

removeSingleton() 方法从多个 Map 中移除即可,DisposableBean 已经被缓存了一份,先删除再销毁也没啥问题。

销毁的主要逻辑在 destroyBean() 中:

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
protected void destroyBean(String beanName, @Nullable DisposableBean bean) {
// 首先触发依赖了当前 Bean 的 Bean 的销毁(dependentBeanMap)
Set<String> dependencies;
synchronized (this.dependentBeanMap) {
// Within full synchronization in order to guarantee a disconnected Set
dependencies = this.dependentBeanMap.remove(beanName);
}
if (dependencies != null) {
// 省略日志的打印
for (String dependentBeanName : dependencies) {
// 递归销毁
destroySingleton(dependentBeanName);
}
}

// 现在销毁自己
if (bean != null) {
try {
bean.destroy();
}
catch (Throwable ex) {
// 省略日志的打印
}
}

// 触发当前 Bean 包含的 Bean 的销毁(containedBeanMap)
Set<String> containedBeans;
synchronized (this.containedBeanMap) {
// Within full synchronization in order to guarantee a disconnected Set
containedBeans = this.containedBeanMap.remove(beanName);
}
if (containedBeans != null) {
for (String containedBeanName : containedBeans) {
// 同样递归销毁
destroySingleton(containedBeanName);
}
}

// Remove destroyed bean from other beans' dependencies.
// 将已销毁的 Bean 从其他 Bean 的依赖关系中移除
// 也就是移除其他 Bean 对已销毁 Bean 的依赖(dependentBeanMap)
synchronized (this.dependentBeanMap) {
for (Iterator<Map.Entry<String, Set<String>>> it = this.dependentBeanMap.entrySet().iterator(); it.hasNext();) {
Map.Entry<String, Set<String>> entry = it.next();
Set<String> dependenciesToClean = entry.getValue();
dependenciesToClean.remove(beanName);
if (dependenciesToClean.isEmpty()) {
it.remove();
}
}
}

// Remove destroyed bean's prepared dependency information.
// 删除已销毁 Bean 的准备好的依赖关系信息(dependenciesForBeanMap)
this.dependenciesForBeanMap.remove(beanName);
}

逻辑分为几步:

  1. 首先在 dependentBeanMap 中移除 (一个递归操作) 其他 Bean 对目标 Bean 的依赖,依赖的都没了,那它自己也该被销毁;
  2. 执行目标 Bean 的销毁(DisposableBean 的执行时机);
  3. containedBeanMap 中移除当前 Bean 包含的 Bean;
  4. 从其他 Bean 的依赖项中删除销毁的目标 Bean;
  5. 最终删除目标 Bean 对其他 Bean 的依赖关系信息。

14. 智能生命周期

14.1 拓展点的作用

智能生命周期,即:SmartLifecycle,它并非 SpringBoot 提供,是在 Spring 中就存在的:

classDiagram
direction BT
class Lifecycle {
<<Interface>>
  + stop() void
  + isRunning() boolean
  + start() void
}
class Phased {
<<Interface>>
  + getPhase() int
}
class SmartLifecycle {
<<Interface>>
  + getPhase() int
  + stop(Runnable) void
  + isAutoStartup() boolean
}

SmartLifecycle  -->  Lifecycle 
SmartLifecycle  -->  Phased

它继承了 Lifecycle 接口和 Phased 接口,一共定义了六个方法:

方法 作用
start() Spring 刷新上下文的最后一步,Bean 初始化完成后,执行该方法
stop() Spring 容器关闭时,执行 Lifecyclestop() 方法
isRunning() 判断当前组件是否在运行
getPhase() 存在多个组件时的回调顺序。值越大,越先执行 start() 方法,越晚执行 stop() 方法
isAutoStartup() 判断是否需要执行 start() 方法,返回 true 才执行
stop(Runnable callback) Spring 容器关闭时,执行 SmartLifecyclestop(Runnable callback) 方法

对于 SmartLifecycle 来说,在容器关闭时,只会 执行它的 stop(Runnable callback) 方法,不会 执行 stop() 方法。

DisposableBeandestroy() 方法类似,两个 stop() 方法也与 SpringBoot Shutdown Hook 有关。

14.2 Lifecycle

先从 Lifecycle 入手,它提供了三个抽象方法,重写它们并将实现类交由 Spring 管理:

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
@Component
static class MyLifecycle implements Lifecycle {

private boolean running = true;

@Override
public void start() {
System.out.printf("[%s]: lifecycle start\n", getCurrentThreadName());
}

@Override
public void stop() {
System.out.printf("[%s]: lifecycle stop\n", getCurrentThreadName());
this.running = false;
}

@Override
public boolean isRunning() {
return this.running;
}
}

public static String getCurrentThreadName() {
return Thread.currentThread().getName();
}

直接使用 close() 方法关闭 Spring 容器:

1
2
3
4
5
6
7
8
9
@SpringBootApplication
public class A15ExtensionPoint {
public static void main(String[] args) {
ConfigurableApplicationContext context =
SpringApplication.run(A15ExtensionPoint.class);
// System.exit(0);
context.close();
}
}
[main]: lifecycle stop

在容器启动时并没有执行 start() 方法,但在容器关闭时执行了 close() 方法。

这是因为在 SpringBoot 应用启动过程中并没有 显式 调用 AbstractApplicationContext#start(),而是调用 AbstractApplicationContext#finishRefresh(),但在应用退出(Spring 容器关闭)时会执行 Lifecycle#isRunning() 方法判断组件是否正在运行,如果返回 true 则会调用 Lifecycle#stop() 方法,这些在后续源码分析中介绍。

那么问题来了,要显式调用 AbstractApplicationContext#start() 才会执行 Lifecyclestart() 方法,但 SpringBoot 在容器启动时并不会显式调用,那 start() 方法岂不是很尴尬?

此时需要一个更“智能”的类,也就是 SmartLifecycle

14.3 SmartLifecycle

它继承了 LifecyclePhased,相比于 LifecycleSmartLifecycle 提供了自动执行 start() 方法的能力,并且具有执行编排(存在多个 SmartLifecycle 时能够控制对应方法的执行顺序)的能力:

  • 重写 isAutoStartup() 方法,并返回 true,使得在容器刷新完成后 自动 执行 start() 方法;
  • 重写 getPhase() 方法,根据返回值的大小编排多个 SmartLifecycle 的执行顺序,值越大,越先执行 start() 方法,越靠后执行 stop() 方法;
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
@Component
static class FirstSmartLifecycle implements SmartLifecycle {

private boolean running = false;

@Override
public void start() {
System.out.printf("[%s]: first start\n", getCurrentThreadName());
this.running = true;
}

@Override
public void stop() {
// 非 SmartLifecycle 的子类才执行
System.out.printf("[%s]: first stop\n", getCurrentThreadName());
this.running = false;
}

@Override
public boolean isRunning() {
return this.running;
}

@Override
public void stop(Runnable callback) {
System.out.printf("[%s]: first stop(Runnable)\n", getCurrentThreadName());
// 显式调用 callback
callback.run();
this.running = false;
}

@Override
public int getPhase() {
return 1;
}
}

@Component
static class SecondSmartLifecycle implements SmartLifecycle {

private boolean running = false;

@Override
public void start() {
System.out.printf("[%s]: second start\n", getCurrentThreadName());
this.running = true;
}

@Override
public void stop() {
System.out.printf("[%s]: second stop\n", getCurrentThreadName());
this.running = false;
}

@Override
public boolean isRunning() {
return this.running;
}

@Override
public void stop(Runnable callback) {
System.out.printf("[%s]: second stop(Runnable)\n", getCurrentThreadName());
callback.run();
this.running = false;
}

@Override
public int getPhase() {
return 2;
}
}
[main]: first start
[main]: second start
[main]: second stop(Runnable)
[main]: first stop(Runnable)

对于 SmartLifecycle 来说,在容器关闭时不会执行父类 Lifecyclestop() 方法,而是执行自身提供的 stop(Runnable callback) 方法。

14.4 容器启动时

在熟悉的 AbstractApplicationContext#refresh() 方法中,所有单例 Bean 都实例化完成后,会执行 finishRefresh() 方法,源码中的注释表明这是 refresh 的最后一步,发布相关的事件:

1
2
// Last step: publish corresponding event.
finishRefresh();

进入该方法内部:

1
2
3
4
5
6
7
8
9
10
11
12
13
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));
}

重点放在中间的两步,它们一个用于初始化 Lifecycle 处理器,一个用于调用 Lifecycle 处理器的 onRefresh() 方法。

initLifecycleProcessor()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@Nullable
private LifecycleProcessor lifecycleProcessor;

public static final String LIFECYCLE_PROCESSOR_BEAN_NAME = "lifecycleProcessor";

// --snip--

protected void initLifecycleProcessor() {
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (beanFactory.containsLocalBean(LIFECYCLE_PROCESSOR_BEAN_NAME)) {
this.lifecycleProcessor =
beanFactory.getBean(LIFECYCLE_PROCESSOR_BEAN_NAME, LifecycleProcessor.class);
// 省略日志的打印
}
else {
DefaultLifecycleProcessor defaultProcessor = new DefaultLifecycleProcessor();
defaultProcessor.setBeanFactory(beanFactory);
this.lifecycleProcessor = defaultProcessor;
beanFactory.registerSingleton(LIFECYCLE_PROCESSOR_BEAN_NAME, this.lifecycleProcessor);
// 省略日志的打印
}
}

方法内部逻辑比较简单,首先获取 BeanFactory,判断容器中是否存在名为 lifecycleProcessor 的 Bean:

  • 如果存在,就获取这个 Bean,并将其赋值给成员变量 this.lifecycleProcessor
  • 如果不存在,自行实例化 DefaultLifecycleProcessor,将其赋值给成员变量 this.lifecycleProcessor,然后再把这个对象注册到 Spring 容器中。

现在已经拿到了 LifecycleProcessor,接下来就是调用它的 onRefresh() 方法了。

getLifecycleProcessor().onRefresh()

来到 DefaultLifecycleProcessor#onRefresh() 方法:

1
2
3
4
5
@Override
public void onRefresh() {
startBeans(true);
this.running = true;
}

再进入 startBeans() 方法:

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
private void startBeans(boolean autoStartupOnly) {
// 获取所有 Lifecycle 类型的 Bean,key 为 Bean 的 name
Map<String, Lifecycle> lifecycleBeans = getLifecycleBeans();
// LifecycleGroup 是对一组 Lifecycle 的封装,可以看成是 List<Lifecycle>
Map<Integer, LifecycleGroup> phases = new TreeMap<>();

// 遍历这些 Bean
lifecycleBeans.forEach((beanName, bean) -> {
// autoStartupOnly == true
// 判断 Bean 是否是 SmartLifecycle 类型,并且其 isAutoStartup() 方法是否返回 true
// 这里只针对 SmartLifecycle 进行了判断,这也是没有执行 Lifecycle#start() 方法的原因
if (!autoStartupOnly || (bean instanceof SmartLifecycle smartLifecycle && smartLifecycle.isAutoStartup())) {
// 获取 phase 值,SmartLifecycle 继承了 Phased,实现类可以设置 phase 值
int phase = getPhase(bean);
// 将相同 phase 值的 Bean 分在一组
phases.computeIfAbsent(
phase,
p -> new LifecycleGroup(phase, this.timeoutPerShutdownPhase, lifecycleBeans, autoStartupOnly)
).add(beanName, bean);
}
});
if (!phases.isEmpty()) {
// 执行每组 SmartLifecycle 的 start 方法
phases.values().forEach(LifecycleGroup::start);
}
}

获取到所有 Lifecycle 后,对它们进行过滤并分组,然后执行它们的 start() 方法。执行逻辑由 LifecycleGroup#start() 完成:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public void start() {
// this.members 就是每组 Lifecycle
// 只不过将 Bean 的 name 和 Bean 实例又包成了 LifecycleGroupMember 对象
if (this.members.isEmpty()) {
return;
}
if (logger.isDebugEnabled()) {
logger.debug("Starting beans in phase " + this.phase);
}
// LifecycleGroupMember 实现了 Comparable 接口,按 phased 值升序排序
Collections.sort(this.members);
for (LifecycleGroupMember member : this.members) {
// 执行 start() 方法
doStart(this.lifecycleBeans, member.name, this.autoStartupOnly);
}
}

对每组 Lifecyclephased 值升序排序,排序完成后依次调用 doStart() 方法。Spring 中喜欢将真正执行逻辑的方法名以 do 开头,可以断定此处的 doStart() 方法是真的用来执行 Lifecycle#start() 方法的:

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
private void doStart(Map<String, ? extends Lifecycle> lifecycleBeans, String beanName, boolean autoStartupOnly) {
// 先从集合中移除要执行 start() 方法的 Lifecycle
Lifecycle bean = lifecycleBeans.remove(beanName);
// 成功移除,并且移除的不是当前 DefaultLifecycleProcessor 实例
if (bean != null && bean != this) {
// 获取依赖了当前 Bean 的 Bean
String[] dependenciesForBean = getBeanFactory().getDependenciesForBean(beanName);
for (String dependency : dependenciesForBean) {
// 递归调用,优先执行依赖了当前 Bean 的 Bean 的 start() 方法
doStart(lifecycleBeans, dependency, autoStartupOnly);
}
// Bean 不处于运行状态
if (!bean.isRunning() &&
// autoStartupOnly 是 false,但传入的 true,这个条件不满足
// Bean 不是 SmartLifecycle 实例,这也不满足,这些 Bean 都是 SmartLifecycle 实例
// SmartLifecycle 的 isAutoStartup() 方法返回 true
(!autoStartupOnly || !(bean instanceof SmartLifecycle smartLifecycle) || smartLifecycle.isAutoStartup())) {
// 省略日志的打印
try {
// 调用 start() 方法
bean.start();
}
catch (Throwable ex) {
// 抛了个 ApplicationContextException
}
// 省略日志的打印
}
}
}

先获取 Bean 的依赖项,递归调用执行依赖项的 start() 方法,之后才执行 start() 方法。

14.5 容器关闭时

在分析 DisposableBean 的执行逻辑时,调用的 AbstractApplicationContext#close() 方法又会调用 AbstractApplicationContext#doClose() 方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
protected void doClose() {
// Check whether an actual close attempt is necessary...
if (this.active.get() && this.closed.compareAndSet(false, true)) {
// --snip--

// Stop all Lifecycle beans, to avoid delays during individual destruction.
if (this.lifecycleProcessor != null) {
try {
this.lifecycleProcessor.onClose();
}
catch (Throwable ex) {
// 省略日志的打印
}
}

// --snip--
}
}

内部会调用 this.lifecycleProcessor.onClose(),通过前文的分析可知,这里调用的是 DefaultLifecycleProcessoronClose() 方法:

1
2
3
4
5
@Override
public void onClose() {
stopBeans();
this.running = false;
}

再进入 stopBeans() 方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
private void stopBeans() {
Map<String, Lifecycle> lifecycleBeans = getLifecycleBeans();
Map<Integer, LifecycleGroup> phases = new HashMap<>();
lifecycleBeans.forEach((beanName, bean) -> {
int shutdownPhase = getPhase(bean);
LifecycleGroup group = phases.get(shutdownPhase);
if (group == null) {
group = new LifecycleGroup(shutdownPhase, this.timeoutPerShutdownPhase, lifecycleBeans, false);
phases.put(shutdownPhase, group);
}
group.add(beanName, bean);
});
if (!phases.isEmpty()) {
List<Integer> keys = new ArrayList<>(phases.keySet());
keys.sort(Collections.reverseOrder());
for (Integer key : keys) {
// 执行每组 LifecycleGroup 的 stop() 方法
phases.get(key).stop();
}
}
}

这里和前文的 startBeans(boolean autoStartupOnly) 方法很类似,对容器中的所有 Lifecyclephased 值进行分组,逆序排序后一一执行。

说句题外话:stopBeans() 的实现其实可以 startBeans() 保持一致,即引入 TreeMap,更简单地使用 Map#computeIfAbsent() 实现分组,但我发现这点并想向 Spring 提交 PR 时,却发现在 4 月已经存在被合并的相关 PR,可惜向 Spring 提交 PR 的计划泡汤了。本文使用的 Spring 版本是此时最新的 6.0.12,不知道修改会在哪个版本上生效呢?👻

回到正题,继续看 LifecycleGroup#stop() 里的逻辑:

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
public void stop() {
if (this.members.isEmpty()) {
return;
}
// 省略日志的打印
// 逆序排序(已经排序,没有意义)
this.members.sort(Collections.reverseOrder());
// 引入 CountDownLatch,数量等于当前 Lifecycle 分组中元素的数量
CountDownLatch latch = new CountDownLatch(this.smartMemberCount);
// 再引入同步 Set,这玩意其实是用来记录日志的,主要逻辑和它关系不大
Set<String> countDownBeanNames = Collections.synchronizedSet(new LinkedHashSet<>());
// 包含当前 Lifecycle 分组中所有 Bean 的 name
Set<String> lifecycleBeanNames = new HashSet<>(this.lifecycleBeans.keySet());
for (LifecycleGroupMember member : this.members) {
if (lifecycleBeanNames.contains(member.name)) {
doStop(this.lifecycleBeans, member.name, latch, countDownBeanNames);
}
else if (member.bean instanceof SmartLifecycle) {
// Already removed: must have been a dependent bean from another phase
latch.countDown();
}
}
try {
// 阻塞下,直到所有 Lifecycle 都执行完或者达到指定超时时间,默认 30 秒
latch.await(this.timeout, TimeUnit.MILLISECONDS);
// 省略日志的打印
}
catch (InterruptedException ex) {
Thread.currentThread().interrupt();
}
}

这个方法内部有两个要点:

  1. 引入 CountDownLatch
  2. 引入 lifecycleBeanNames,并在遍历每个 Lifecycle 时,执行 contains() 方法。

为了提高执行效率,在实现 SmartLifecycle 接口重写 stop(Runnable callback) 方法时,可以开一个线程中执行内部逻辑,使多个 SmartLifecyclestop() 方法并行执行。

当前线程必须等待所有执行 stop() 方法的线程执行完才继续向下执行,因此引入了 CountDownLatch

假设有两个 Bean 分别叫 A 和 B,A 依赖了 B,但 A 的 phased 小于 B,因此会先执行 B 的 stop() 方法。在执行了 B 的 stop() 方法时,发现 A 依赖了它,于是会更先一步执行 A 的 stop() 方法,之后再执行 B 的 stop() 方法。等到 B 的 stop() 执行完,按照 phased 的大小,接下来应该执行 A 的 stop() 方法,但由于 A 的 stop() 方法在先前已经执行过了,再来一遍肯定是不合适的,因此引入 lifecycleBeanNames 判断 A 不在该集合中,那么直接执行 CountDownLatch#countDown() 即可。这里涉及到 doStop() 方法的分析,它内部有什么奥秘呢?

doStart() 方法类似,doStop() 也是用来真正执行 Lifecycle#stop() 的,其处理逻辑也和 doStart() 类似:

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
private void doStop(Map<String, ? extends Lifecycle> lifecycleBeans, final String beanName,
final CountDownLatch latch, final Set<String> countDownBeanNames) {
// 先从集合中移除要执行 stop() 方法的 Lifecycle
Lifecycle bean = lifecycleBeans.remove(beanName);
if (bean != null) {
// 和 doStart() 方法类似,先处理依赖了当前 Bean 的 Bean
String[] dependentBeans = getBeanFactory().getDependentBeans(beanName);
for (String dependentBean : dependentBeans) {
doStop(lifecycleBeans, dependentBean, latch, countDownBeanNames);
}
try {
// 如果 Bean 正在运行
if (bean.isRunning()) {
// Bean 还是 SmartLifecycle 类型
if (bean instanceof SmartLifecycle smartLifecycle) {
// 省略日志的打印
countDownBeanNames.add(beanName);
// 执行 SmartLifecycle 的 stop(Runnable) 方法
smartLifecycle.stop(() -> {
// 内部调用了 CountDownLatch#countDown()
latch.countDown();
countDownBeanNames.remove(beanName);
// 省略日志的打印
});
}
else {
// 省略日志的打印
// 不是 SmartLifecycle 类型,直接调用 stop() 方法
bean.stop();
// 省略日志的打印
}
}
else if (bean instanceof SmartLifecycle) {
// Don't wait for beans that aren't running...
latch.countDown();
}
}
catch (Throwable ex) {
// 省略日志的打印
}
}
}

实现还是比较简单,但有一个重要的注意点:如果 Bean 的类型是 SmartLifecycle 时,传入了一个 Runnable,并且 Runnable 中执行了 CountDownLatch#countDown(),这要求 在重写 stop(Runnable callback) 方法时一定要在内部调用 callback.run(),否则 CountDownLatch 的计数减不下去,就会在达到设置的超时时间前一直阻塞线程。

15. Spring 生命周期

Spring 的生命周期,其实指的是 Spring Bean 的生命周期,Bean 的生命周期概括起来共三步:

  1. 将 Java 类抽象为 BeanDefinition 对象;
  2. 根据 BeanDefinition 对象完成 Bean 的实例化、初始化和其他拓展操作;
  3. 使用 Spring 管理的 Bean,直至销毁。

前文花了大量篇幅介绍 SpringBoot 的拓展点,而这些拓展点是贯穿 Bean 的生命周期的,按照执行先后可以绘制出包含大多数拓展点的执行流程图:

SpringBoot拓展点流程图

16. 总结

本文介绍了 BeanFactory 周围、Bean 实例化周围、Bean 初始化周围共十多个拓展点,每个拓展点分为作用、使用方式、实例化(注册)、执行、内置实现等小节,并结合源码进行讲解,最终将这些拓展点汇总指向 Spring Bean 的生命周期。

行文过程中留下了一些坑:

  • getBean() 方法源码分析
  • AOP 源码分析
  • Spring 循环依赖源码分析
  • Spring Shutdown Hook

这些内容慢慢来吧,今年应该能够整完?! 🤔