invokeBeanDefinitionRegistryPostProcessors方法解析

前言

首先来回顾一下上周学习的内容。在上周我们主要解析了refresh()方法中的invokeBeanFactoryPostProcessors(beanFactory)方法。这个方法主要是实例化并调用所有注册的BeanFactoryPostProcessor,我们也知道了invokeBeanFactoryPostProcessors方法中主要是处理BeanFactoryPostProcessor接口的,而BeanFactoryPostProcessor是针对BeanFactory的扩展,所以在bean实例化之前,可以读取bean定义,也可以修改bean定义。同时我们说到了在第一次调用bean定义后置处理器的时候会去解析我们的@Import@Component等注解,而解析这个注解又调用了invokeBeanDefinitionRegistryPostProcessors方法,在这个方法中最终会调用ConfigurationClassPostProcessor类中的processConfigBeanDefinitions方法。上周 没有讲到这个方法,下来我们详细说一下。

一、processConfigBeanDefinitions方法调用链

processConfigBeanDefinitions方法调用链

跟着processConfigBeanDefinitions方法调用链我们找到这个方法如下图

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
146
147
148
149
150
151
152
153
154
155
156
157
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
/**
* 获得所有的BeanDefinition的Name,存放到candidateNames
*/
String[] candidateNames = registry.getBeanDefinitionNames();

/**
* 循环从所有BeanDefinition拿到配置类并且标记:CONFIGURATION_CLASS_ATTRIBUTE属性
* CONFIGURATION_CLASS_ATTRIBUTE属性分两种:
* full完整配置类:@Configuration
* lite精简版配置类:@Component@Import@ComponentScan@Bean@ImportSource
*
* 内部有两个标记位来标记是否已经处理过了,这里也会有一串只是盲区
* 当我们注册配置类的时候,可以不加@Configuration注解,直接使用@Component@ComponentScan@Import@ImportSource注解,这时候我们称这个类叫Lite配置类
* 如果类上加了@Configuration注解,我们称这类叫Full配置类
* 如果我们注册了Lite配置类,那么我们getBean(...)这个配置类的时候,会发现他就是原本的那个配置类。
* 如果我们注册了Full配置类,那么我们getBean(...)这个配置类的时候,会发现他已经不是原本的那个配置类了,反而已经成CGLIB代理的类了。
*
*
*/
for (String beanName : candidateNames) {
BeanDefinition beanDef = registry.getBeanDefinition(beanName);
if (beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE) != null) {
if (logger.isDebugEnabled()) {
logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
}
}
/**
* 检查bean是否是configutation类,同时这里会设置bean定义的元数据以及CONFIGURATION_CLASS_ATTRIBUTE属性(full/lite)
* 判断是否为配置类,在ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef,this.metadataReaderFactory)
* 内部会做判断,这个类是Full配置类还是Lite配置类,并给CONFIGURATION_CLASS_ATTRIBUTE属性加上full/lite标记
* 满足条件下将bean定义封装成BeanDefinitionHolder并加入到configCandidates中
*/
else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
}
}

// Return immediately if no @Configuration classes were found
/** 如果没有注解@Configuration类则返回 */
if (configCandidates.isEmpty()) {
return;
}

// Sort by previously determined @Order value, if applicable
/** 按照注解中@Order给定的顺序排序 */
configCandidates.sort((bd1, bd2) -> {
int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
return Integer.compare(i1, i2);
});

// Detect any custom bean name generation strategy supplied through the enclosing application context
SingletonBeanRegistry sbr = null;
/**
* registry是DefaultListableBeanFactory类型,DefaultListableBeanFactory最终会实现SingletonBeanRegistry接口
* 所以可以进入这个if
*/
if (registry instanceof SingletonBeanRegistry) {
sbr = (SingletonBeanRegistry) registry;
if (!this.localBeanNameGeneratorSet) {
/**
* spring中可以修改默认的bean命名方式,这里就是看用户有没有自定义bean的命名方式。
* 如果有自定义bean命名方式,那么会用自定义的bean命名方式替换掉默认命名方式
*/
BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(
AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR);
if (generator != null) {
this.componentScanBeanNameGenerator = generator;
this.importBeanNameGenerator = generator;
}
}
}

if (this.environment == null) {
this.environment = new StandardEnvironment();
}

// Parse each @Configuration class
/**
* 创建配置类解析器
* 解析@Component@ComponentScan@Import@Bean@ImportSource
*/
ConfigurationClassParser parser = new ConfigurationClassParser(
this.metadataReaderFactory, this.problemReporter, this.environment,
this.resourceLoader, this.componentScanBeanNameGenerator, registry);

Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
do {
/** 这里真正的解析注解,解析配置类,@Components@ComponentScan@Import等 */
parser.parse(candidates);
parser.validate();

Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
configClasses.removeAll(alreadyParsed);

// Read the model and create bean definitions based on its content
/** 通过ConfigurationClassBeanDefinitionReader读取配置数据,并且根据他的内容创建一个Bean定义 */
if (this.reader == null) {
this.reader = new ConfigurationClassBeanDefinitionReader(
registry, this.sourceExtractor, this.resourceLoader, this.environment,
this.importBeanNameGenerator, parser.getImportRegistry());
}
/**
* 注册bean定义
* 这一步才会把@Import@Bean@ImportSource注解的类转化成BeanDefinition
*/
this.reader.loadBeanDefinitions(configClasses);
/**
* 把configClasses加入到alreadyParsed
*/
alreadyParsed.addAll(configClasses);

candidates.clear();
/**
* 获取注册器里面BeanDefinition的数量和candidateNames进行比较
* 如果大于的话,说明有新的BeanDefinition注册进来
*/
if (registry.getBeanDefinitionCount() > candidateNames.length) {
/** 从注册器里获取BeanDefinitionNames */
String[] newCandidateNames = registry.getBeanDefinitionNames();
/** candidateNames转化为set */
Set<String> oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames));
Set<String> alreadyParsedClasses = new HashSet<>();
/** 循环alreadyParsed,把ConfigurationClass加入到alreadyParsedClasses */
for (ConfigurationClass configurationClass : alreadyParsed) {
alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
}
for (String candidateName : newCandidateNames) {
if (!oldCandidateNames.contains(candidateName)) {
BeanDefinition bd = registry.getBeanDefinition(candidateName);
/** checkConfigurationClassCandidate(...)判断bean是否符合注入条件 */
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&
!alreadyParsedClasses.contains(bd.getBeanClassName())) {
candidates.add(new BeanDefinitionHolder(bd, candidateName));
}
}
}
candidateNames = newCandidateNames;
}
}
while (!candidates.isEmpty());

// Register the ImportRegistry as a bean in order to support ImportAware @Configuration classes
/** 将 ImportRegistry 注册为 bean 以支持 ImportAware @Configuration 类 */
if (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
}

if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {
// Clear cache in externally provided MetadataReaderFactory; this is a no-op
// for a shared cache since it'll be cleared by the ApplicationContext.
((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache();
}
}

二、解析

找到方法实现之后,接下来我们对方法中逻辑做一下解释。

1、获取所有BeanName

1
2
/** 获得所有的BeanDefinition的Name,存放到candidateNames */
String[] candidateNames = registry.getBeanDefinitionNames();

来获取所有BeanName,并将其放入candidateNames数组中;

2、循环candidateNames数组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
for (String beanName : candidateNames) {
BeanDefinition beanDef = registry.getBeanDefinition(beanName);
if (beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE) != null) {
if (logger.isDebugEnabled()) {
logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
}
}
/**
* 检查bean是否是configutation类,同时这里会设置bean定义的元数据以及CONFIGURATION_CLASS_ATTRIBUTE属性(full/lite)
* 判断是否为配置类,在ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef,this.metadataReaderFactory)
* 内部会做判断,这个类是Full配置类还是Lite配置类,并给CONFIGURATION_CLASS_ATTRIBUTE属性加上full/lite标记
* 满足条件下将bean定义封装成BeanDefinitionHolder并加入到configCandidates中
*/
else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
}
}

循环在第一步获取到的candidateNames数组,根据beanName获得BeanDefinition,判断此BeanDefinition是否已经被处理过了;接着会判断是否为配置类,如果是的话。加入到configCandidates数组;在判断的时候还会标记配置类是属于Full配置类还是属于Lite配置类。

扫盲点:

  1. 当注册配置类的时候,可以不加@Configuration注解,直接使用@Component@ComponentScan@Import@ImportResource等注解,在Spring中这类的配置类称为Lite配置类,如果加了@Component注解,就称之为Full配置类。
  2. 如果注册了Lite配置类,当我们在使用getBean()获取这配置类时,会发现他就是原本的那个配置类,如果我们注册了Full配置类,再通过getBean()获取这个配置类的时候,会发现他已经不是原来的那个配置类了,而是被CGLIB代理之后的类。
  3. 写一个A类,其中有一个构造方法,打印出”hello word”,在写一个配置类,里面有两个被@Bean注解的方法,其中一个方法new 了A类,并且返回A对象,把此方法称之为getA,第二个方法有调用了getA方法,如果配置类是Lite配置类,会发现打印了两次”hello word”,也就是说A类被new了两次,如果配置类是Full配置类,会发现只打印一次”hello word”,也就是说A类被new了一次,这是因为这个类被CGLIB代理了,方法已经被改写了。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class A {
public A(){System.out.println("hello word");}
}

@Configuration // 只会打印一次"hello word"
@Component // 会打印两次"hello Word"
public class B {
@AutoWired
private A a;

@Bean
public A getA() {
return new A();
}

@Bean
public A getA2() {
return getA();
}
}

3、是否有注解@Configuration

1
2
3
if (configCandidates.isEmpty()) {
return;
}

判断bean有没有被@Configuration标记,如果没有被标记说明不是配置类,直接返回

4、根据@Order排序

1
2
3
4
5
configCandidates.sort((bd1, bd2) -> {
int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
return Integer.compare(i1, i2);
});

这里会按照@Order中指定的顺序进行排序

5、解析配置类

通过parser.parse方法来解析配置类,改配置类可能是Full配置类,也可能是Lite配置类,进入到这个方法中看一看

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
public void parse(Set<BeanDefinitionHolder> configCandidates) {
for (BeanDefinitionHolder holder : configCandidates) {
BeanDefinition bd = holder.getBeanDefinition();
try {
/**
* 如果BeanDefinition是AnnotatedBeanDefinition实例,解析注解
*/
if (bd instanceof AnnotatedBeanDefinition) {
/** 解析配置类,@Component@Components@Import等 */
parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
}
else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {
parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());
}
else {
parse(bd.getBeanClassName(), holder.getBeanName());
}
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(
"Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex);
}
}

this.deferredImportSelectorHandler.process();
}

因为这里可以配置多个配置类,所以需要做循环处理,因为我们的配置类是AnnotatedBeanDefinition的实例,所以这里会进入到第一个if中的parse()方法中,我们继续点进入看一看逻辑

1
2
3
protected final void parse(AnnotationMetadata metadata, String beanName) throws IOException {
processConfigurationClass(new ConfigurationClass(metadata, beanName), DEFAULT_EXCLUSION_FILTER);
}
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
protected void processConfigurationClass(ConfigurationClass configClass, Predicate<String> filter) throws IOException {
/**
* 判断是否跳过注解,解析@Conditional注解
*/
if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
return;
}

ConfigurationClass existingClass = this.configurationClasses.get(configClass);
if (existingClass != null) {
if (configClass.isImported()) {
if (existingClass.isImported()) {
existingClass.mergeImportedBy(configClass);
}
// Otherwise ignore new imported config class; existing non-imported class overrides it.
return;
}
else {
// Explicit bean definition found, probably replacing an import.
// Let's remove the old one and go with the new one.
this.configurationClasses.remove(configClass);
this.knownSuperclasses.values().removeIf(configClass::equals);
}
}

// Recursively process the configuration class and its superclass hierarchy.
/** 递归处理配置类及其子类的层次结构 */
SourceClass sourceClass = asSourceClass(configClass, filter);
do {
/**
* 重点关注的方法
* 解析注解@Component@ComponentScan@Components@Import
*/
sourceClass = doProcessConfigurationClass(configClass, sourceClass, filter);
}
while (sourceClass != null);

this.configurationClasses.put(configClass, configClass);
}

这个方法中进行了判断,以及递归配置类,最终调用doProcessConfigurationClass,来正则实现解析注解

6、doProcessConfigurationClass执行真正解析注解

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
@Nullable
protected final SourceClass doProcessConfigurationClass(
ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter)
throws IOException {

/** 解析注解@Component */
if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
// Recursively process any member (nested) classes first
processMemberClasses(configClass, sourceClass, filter);
}

// Process any @PropertySource annotations
/** 解析注解@PropertySource@PropertySource注解用来加载properties文件 */
for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getMetadata(), PropertySources.class,
org.springframework.context.annotation.PropertySource.class)) {
if (this.environment instanceof ConfigurableEnvironment) {
processPropertySource(propertySource);
}
else {
logger.info("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +
"]. Reason: Environment must implement ConfigurableEnvironment");
}
}

// Process any @ComponentScan annotations
/** 解析注解@ComponentScan@ComponentScan注解除了常用的basePackage之外,还有includeFilters,excludeFilters等属性 */
Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
/** 如果没有加@ComponentScan注解或者用@Condition注解跳过的,就不再进入这个if */
if (!componentScans.isEmpty() &&
!this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
for (AnnotationAttributes componentScan : componentScans) {
// The config class is annotated with @ComponentScan -> perform the scan immediately
/** 如果一个类配置了@ComponentScan注解,则会立即执行parse(...)进行扫描,sourceClass.getMetadata().getClassName()就是配置类的名称 */
Set<BeanDefinitionHolder> scannedBeanDefinitions =
this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
// Check the set of scanned definitions for any further config classes and parse recursively if needed
/** 检查其他的配置类是否设置了扫描定义,并且在需要的是否递归解析 */
for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
if (bdCand == null) {
bdCand = holder.getBeanDefinition();
}
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
// 二次扫描,因为可能组件类有被@Bean标记的方法,或者组件类本身也有@ComponentScan注解,需要再一次扫描
parse(bdCand.getBeanClassName(), holder.getBeanName());
}
}
}
}

// Process any @Import annotations
/** 解析@Import注解
* @Import 注解是spring中很重要的一个注解,SpringBoot中大量应用了这个注解
* @Import 三种类, 一种是@Import普通类,一种是Import ImportSelector,还有一种是Import ImportBeanDefinitionRegister
* getImports(sourceClass)是获取import的内容,返回的是一个set
*/
processImports(configClass, sourceClass, getImports(sourceClass), filter, true);

// Process any @ImportResource annotations
/** 解析@ImportResource注解 */
AnnotationAttributes importResource =
AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
if (importResource != null) {
String[] resources = importResource.getStringArray("locations");
Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
for (String resource : resources) {
String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
configClass.addImportedResource(resolvedResource, readerClass);
}
}

// Process individual @Bean methods
/** 解析@Bean注解 可以看出获取了带@Bean的方法后,不是马上转换成BeanDefinition,而是先用一个set<AnnotationAttributes>接收 */
Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
for (MethodMetadata methodMetadata : beanMethods) {
configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}

// Process default methods on interfaces
/** 解析接口默认方法 */
processInterfaces(configClass, sourceClass);

// Process superclass, if any
/** 解析超类 */
if (sourceClass.getMetadata().hasSuperClass()) {
String superclass = sourceClass.getMetadata().getSuperClassName();
if (superclass != null && !superclass.startsWith("java") &&
!this.knownSuperclasses.containsKey(superclass)) {
this.knownSuperclasses.put(superclass, configClass);
// Superclass found, return its annotation metadata and recurse
return sourceClass.getSuperClass();
}
}

// No superclass -> processing is complete
return null;
}

在这个方法中才是我们关注的重点,这里将会解析@Component@PropertySource@Import@ImportResource@Bean注解,并且他们的解析顺序也是从左到右一次进行解析。

doProcessConfigurationClass解析流程

  • 版权声明: 本博客所有文章除特别声明外,著作权归作者所有。转载请注明出处!

请我喝杯咖啡吧~

支付宝
微信