Spring Bean的生命周期——Bean定义

Spring Bean 的生命周期有4个阶段:Bean 定义、Bean 初始化、Bean 生存期、Bean 销毁。因为“Bean 生存期”阶段就是程序启动后我们使用 Bean 的过程,所以不需要介绍。这篇博客介绍的是“Bean 定义”阶段。

源码版本:SpringBoot 2.3.0,Spring 5.2.6

概述

“Bean定义”是 Spring Bean 的生命周期的第一个阶段,这个阶段里会根据启动类上的注解 @ComponentScan 指定的包路径(默认是当前包及其子包)扫描,把 Bean 定义信息保存到 IoC 容器中,待“Bean 初始化”阶段使用。

SpringBoot Web 应用使用的 IoC 容器为AnnotationConfigServletWebServerApplicationContext,这个容器包含一个属性:beanFactory = DefaultListableBeanFactory 。所有 Bean 定义信息就是保存到 DefaultListableBeanFactory 的成员 Map<String, BeanDefinition> beanDefinitionMap 中。BeanDefinidition 是用来记录 Bean 定义信息的接口,子类有 RootBeanDefinition、AnnotatedGenericBeanDefinition、ScannedGenericBeanDefinition 等。

真正开始注册 Bean 定义信息的时候是容器刷新的时候,即发生在 AbstractApplicationContext.refresh() 中。下面先看看容器刷新前为“Bean 定义”阶段做了哪些工作。

容器刷新前的准备

提前总结:
SpringApplication 先创建容器对象 context = AnnotationConfigServletWebServerApplicationContext,赋值其中成员 beanFactory = DefaultListableBeanFactory。容器对象创建完成后,成员 beanFactory 内已经有少数几个 BeanDefinidition 信息了,其中包括 ConfigurationClassPostProcessor。然后 SpringApplication 向容器对象成员 beanFactory 中注册了启动类 DemoApplication 的 BeanDefinidition。

在 SpringAppliction.run(String… args) 方法中,创建 IoC 容器 AnnotationConfigServletWebServerApplicationContext 时,反射调用该类及其父类们的无参构造方法,初始化成员 beanFactory = DefaultListableBeanFactory。

在容器 AnnotationConfigServletWebServerApplicationContext 自己的无参构造中,初始化成员 reader = AnnotatedBeanDefinitionReader 。在 AnnotatedBeanDefinitionReader 的构造函数中,调用了AnnotationConfigUtils.registerAnnotationConfigProcessors() 方法,这个方法内往容器成员 beanFactory 中注册了几个指定的 Bean 定义(RootBeanDefinition 类型),其中包括 ConfigurationClassPostProcessor ,下面会介绍它。

从 AnnotatedBeanDefinitionReader 源码可以看出,它的作用是手动注册某个 Bean 的定义信息。这个在容器开始扫描所有 Bean 之前很好用,这是因为有一些 Bean 需要在扫描前就被初始化,例如启动类的 Bean。

回到 SpringAppliction.run(String… args) 方法,创建好容器后,调用本类的prepareContext方法,这个方法内最后调用SpringApplication.load()方法。

SpringApplication.load() 部分源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
protected void load(ApplicationContext context, Object[] sources) {
if (logger.isDebugEnabled()) {
logger.debug("Loading source " + StringUtils.arrayToCommaDelimitedString(sources));
}
BeanDefinitionLoader loader = createBeanDefinitionLoader(getBeanDefinitionRegistry(context), sources);
if (this.beanNameGenerator != null) {
loader.setBeanNameGenerator(this.beanNameGenerator);
}
if (this.resourceLoader != null) {
loader.setResourceLoader(this.resourceLoader);
}
if (this.environment != null) {
loader.setEnvironment(this.environment);
}
loader.load();
}

参数1context为已创建的容器对象,参数2sources只有一个元素,就是启动类 Class 对象,如”DemoApplication.class”(来源是 SpringApplication.run() 方法时的第一个参数)。在这个方法内,创建 BeanDefinitionLoader 对象,再通过 BeanDefinitionLoader 对象内成员AnnotatedBeanDefinitionReader(与容器内的 reader 不是同一个对象,但它的成员 registry 与 容器内的 beanFactory 是同一个对象),向容器中注册了启动类 DemoApplication 的 Bean 定义(AnnotatedGenericBeanDefinition 类型)。主要负责这个注册工作的是AnnotatedBeanDefinitionReader.doRegisterBean()方法:

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
private <T> void doRegisterBean(Class<T> beanClass, @Nullable String name,
@Nullable Class<? extends Annotation>[] qualifiers, @Nullable Supplier<T> supplier,
@Nullable BeanDefinitionCustomizer[] customizers) {

// beanClass=启动类Class对象
AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);

// 这一步判断这个bean上是否加了@Conditional注解,加了就不继续
if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
return;
}

abd.setInstanceSupplier(supplier);

// 这一步设置BeanDefinition中的scope属性,若未使用@Scope注解,则取默认值"singleton"
// 同时设置了scopedProxyMode=NO
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
abd.setScope(scopeMetadata.getScopeName());

// 取beanName用于注册,详细说明见下方
String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));

// 对常用注解的处理,如使用了@Lazy则设置lazyInit=true。qualifiers是调用这个方法时手动设置的注解类Class,与bean本身是否使用注解无关
AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
if (qualifiers != null) {
for (Class<? extends Annotation> qualifier : qualifiers) {
if (Primary.class == qualifier) {
abd.setPrimary(true);
}
else if (Lazy.class == qualifier) {
abd.setLazyInit(true);
}
else {
abd.addQualifier(new AutowireCandidateQualifier(qualifier));
}
}
}
// 猜测是给abd任意设置属性的方法
if (customizers != null) {
for (BeanDefinitionCustomizer customizer : customizers) {
customizer.customize(abd);
}
}
// 注册
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
// 这一步判断scopedProxyMode,如果不是NO,则definitionHolder的BeanDefinidition的beanClass=ScopedProxyFactoryBean.class
definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
}

上面源码取 beanName 时,用的是AnnotationBeanNameGenerator.generateBeanName(),当 Bean 定义对象是 AnnotatedBeanDefinition 的子类时(AnnotatedGenericBeanDefinition 就是),用的是下面这个方法:

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
protected String determineBeanNameFromAnnotation(AnnotatedBeanDefinition annotatedDef) {
AnnotationMetadata amd = annotatedDef.getMetadata();
// types是类上直接标注的注解集合
Set<String> types = amd.getAnnotationTypes();
String beanName = null;
for (String type : types) { // 遍历types
// attributes是注解 type 中的所有属性,k-v格式,key=属性名,value=属性值
AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(amd, type);
if (attributes != null) {

// 当type是个复合注解,metaTypes是这个复合注解中所包含的注解集合
Set<String> metaTypes = this.metaAnnotationTypesCache.computeIfAbsent(type, key -> {
Set<String> result = amd.getMetaAnnotationTypes(key);
return (result.isEmpty() ? Collections.emptySet() : result);
});

// 判断type和metaType中是否包含@Component注解
if (isStereotypeWithNameValue(type, metaTypes, attributes)) {
// 取@Component的value属性
Object value = attributes.get("value");
if (value instanceof String) {
String strVal = (String) value;
// 若value属性值有指定,就作为beanName返回
if (StringUtils.hasLength(strVal)) {
// 但如果一个类有多个@Component注解指定了value值,会报错(如@Component和@Service同时存在且同时指定了value)
if (beanName != null && !strVal.equals(beanName)) {
throw new IllegalStateException("Stereotype annotations suggest inconsistent " +
"component names: '" + beanName + "' versus '" + strVal + "'");
}
beanName = strVal;
}
}
}
}
}
return beanName;
}

注释中所说的“复合注解”举例:@SpringBootApplication 下包含 @EnableAutoConfiguration,@EnableAutoConfiguration 下又包含 @Import 等。

这个方法的含义是,从当前 bean 的所有注解中找 @Component 注解,如果有 @Component 注解且指定了 value 属性,则 beanName=value属性值,否则 beanName=null。当这个方法返回的 beanName=null 时,就会用另一个方法:取类名,第一个字母小写。

例如我们的启动类一般不会特意用 @Component 指定 bean 名字(@SpringBootApplication 指定不了),所以启动类的 beanName 就是取类名,第一个字母小写。

问题:注册 Bean 定义时,为什么加了 @Conditional注解就不继续?@Conditional只是控制一个bean在特定条件下才注入。 ???

容器刷新

在 AbstractApplicationContext.refresh() 方法中,调用本类中的 invokeBeanFactoryPostProcessors 方法,参数是 beanFactory = DefaultListableBeanFactory。在这个方法中,又调用了PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors()方法。

PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors() 方法参数1是 beanFactory,参数2是容器中已添加的 BeanFactoryPostProcessor(是在上一节“容器刷新前的准备”阶段添加的, 这里不用关注有哪些)。这个方法的作用是取出容器中当前已保存的、实现了 BeanFactoryPostProcessor 接口的 Bean,并初始化这些 Bean,然后调用这些 Bean 的,以及“参数2”中的 Bean 的 postProcessBeanFactory 方法,若 Bean 实现的接口是 BeanDefinitionRegistryPostProcessor(该接口继承了 BeanFactoryPostProcessor),会先调用其 postProcessBeanDefinitionRegistry 方法,再调用其 postProcessBeanFactory 方法。

【PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors() 方法的详细解读见附录1。

在上一节说过,容器刚创建时就注册了 ConfigurationClassPostProcessor 的 BeanDefinidition 对象,它就是 BeanDefinitionRegistryPostProcessor 接口的实现类,所以在这个方法内会创建并实例化它的 Bean,再调用它的 postProcessBeanDefinitionRegistry 方法。

ConfigurationClassPostProcessor 是在“Bean 定义”阶段最关键的一个类,XXXXXXXXXXXXXXX

这个类做了什么?

1、取出容器当前拥有的 BeanDefinidition 对象,判断它们是否是配置类,不是配置类的不处理,是配置类的继续处理。

这里判断是不是配置类的方法是ConfigurationClassUtils.checkConfigurationClassCandidate。简单地说,类上有这些注解之一的:@Configuration、@Component、@ComponentScan、@Import、@ImportResource,或类中方法有注解 @Bean 的,都算配置类。

PS: 从实际使用经验上来说,类上不标任何注解,只在方法上标注解 @Bean,是不起作用的,原因是这样的类在扫描时就扫不到,更进不到这个判断方法。

在这一步,本身容器中已注册的 BeanDefinidition 就不多,再经过筛选,就只剩下启动类如”DemoApplication”的 BeanDefinidition 会被继续处理了。

@Import 注解可用于导入一个或多个 Bean,它和 @Bean 的区别就是它是标在类上。@ImportResource 类似,但它是用于导入配置文件。

2、如果筛选完有多个配置类的话,若配置类上有标@Order注解,会排个序,按注解value值升序排序,所以值越小的优先级越高。

3、创建ConfigurationClassParser,调用这个类的 parse 方法处理筛选出的配置类 BeanDefinidition 对象(只有启动类一个),这个类最后调用到doProcessConfigurationClass方法。

1
2
3
4
// 参数configClass和sourceClass都是启动类Class对象
protected final SourceClass doProcessConfigurationClass(
ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter)
throws IOException {...}

通过方法内注释可以知道,这个方法会处理被这些注解标注的配置类:@PropertySource(可以和@Value注解配合使用读取配置项)、@ComponentScan、@Import、@ImportResource,和用 @Bean 标注的方法。

已知,Spring 会根据启动类上的 @ComponentScan 注解,扫描启动类所在包下所有的 Bean 定义信息,保存到 beanFactory=DefaultListableBeanFactory 中。这里就来说说 ConfigurationClassParser 是怎么处理 @ComponentScan 注解的。

附录1:PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors()

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

// 保存已经执行过的processor的名字
Set<String> processedBeans = new HashSet<>();

if (beanFactory instanceof BeanDefinitionRegistry) { // 一般都走这个分支,因为 beanFactory=DefaultListableBeanFactory

BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;

// 整理参数2中的processors,把有实现BeanDefinitionRegistryPostProcessor和没实现的分开存放
List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();
for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
BeanDefinitionRegistryPostProcessor registryProcessor =
(BeanDefinitionRegistryPostProcessor) postProcessor;
// 保存前先执行BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry方法
registryProcessor.postProcessBeanDefinitionRegistry(registry);
registryProcessors.add(registryProcessor);
}
else {
regularPostProcessors.add(postProcessor);
}
}
// 用来暂存当前要执行的processor,执行完即清空
List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();

// 从beanFactory中找实现了 BeanDefinitionRegistryPostProcessor 和 PriorityOrdered 接口的Bean,初始化,执行它们的postProcessBeanDefinitionRegistry方法
// 这一步就会执行到 ConfigurationClassPostProcessor 的 postProcessBeanDefinitionRegistry 方法
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); // PriorityOrdered 接口可以定义执行顺序,执行前先排序
registryProcessors.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
currentRegistryProcessors.clear();

// 从beanFactory中找实现了 BeanDefinitionRegistryPostProcessor 和 Ordered 接口的Bean,初始化,执行它们的postProcessBeanDefinitionRegistry方法
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);
currentRegistryProcessors.clear();

// 从beanFactory中找只实现了 BeanDefinitionRegistryPostProcessor 接口的Bean,初始化,执行它们的postProcessBeanDefinitionRegistry方法
// 循环的原因:一个processor可能会添加新的 BeanDefinitionRegistryPostProcessor 接口的Bean,所以循环到找不到新的为止
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);
currentRegistryProcessors.clear();
}

// 遍历调用 registryProcessors 中的 postProcessBeanFactory 方法,registryProcessors 包含参数2中实现了 BeanDefinitionRegistryPostProcessor 的类和前面几次从 beanFactory 中找 BeanDefinitionRegistryPostProcessor 类型的Bean定义生成的Bean
invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
// 遍历调用 regularPostProcessors 中的 postProcessBeanFactory 方法,regularPostProcessors 包含参数2中未实现 BeanDefinitionRegistryPostProcessor 的类
invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
}

else {
// 遍历调用参数2 beanFactoryPostProcessors 中的 postProcessBeanFactory 方法
invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
}

// 下面这部分和上面相似,只是类型换成了 BeanFactoryPostProcessor
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);

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

sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);

List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());
for (String postProcessorName : orderedPostProcessorNames) {
orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
sortPostProcessors(orderedPostProcessors, beanFactory);
invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);

List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
for (String postProcessorName : nonOrderedPostProcessorNames) {
nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);

// beanFactory清除缓存
beanFactory.clearMetadataCache();
}

总结这个方法做的事:

  1. 执行 BeanDefinitionRegistryPostProcessor 类型的、实现了 PriorityOrdered 接口的 postProcessor 的 postProcessBeanDefinitionRegistry 方法 — 这里会执行到 ConfigurationClassPostProcessor
  2. 执行 BeanDefinitionRegistryPostProcessor 类型的、实现了 Ordered 接口的 postProcessor 的 postProcessBeanDefinitionRegistry 方法
  3. 执行 BeanDefinitionRegistryPostProcessor 类型的、没有实现 PriorityOrdered/Ordered 接口的 postProcessor 的 postProcessBeanDefinitionRegistry 方法
  4. 执行方法参数中实现了 BeanDefinitionRegistryPostProcessor 的,和前面三步的BeanDefinitionRegistryPostProcessor 类型的 postProcessor 的 postProcessBeanFactory 方法
  5. 执行方法参数中未实现 BeanDefinitionRegistryPostProcessor 的 postProcessor 的 postProcessBeanFactory 方法
  6. 执行 BeanFactoryPostProcessor 类型的、实现了 PriorityOrdered 接口的 postProcessor 的 postProcessBeanFactory 方法
  7. 执行 BeanFactoryPostProcessor 类型的、实现了 Ordered 接口的 postProcessor 的 postProcessBeanFactory 方法
  8. 执行 BeanFactoryPostProcessor 类型的 postProcessor 的 postProcessBeanFactory 方法