Spring的Bean的注册

Bean的注册

在上一篇文章中提到了在使用invokeBeanFactoryPostProcessors(beanFactory) 方法中,
调用了 ConfigurationClassPostProcessor 中的 postProcessBeanDefinitionRegistry 方法,
实现了对configuration配置文件中的内容得到加载和解析。完成对标注为Bean的方法注册「regist」到容器中。

下面就针对这一注册配置文件内的Bean的过程进行源码的分析:

ConfigurationClassPostProcessor

invokeBeanFactoryPostProcessor 方法中,
循环调用类中的后置方法 postProcessBeanDefinitionRegistry ,
其中包括了 ConfigurationClassPostProcessor 类。
根据名字也能看出这个类是配置文件类的后置处理类。那么就之间看代码,了解配置文件的后置处理器都做了些什么。

1
2
3
4
5
6
7
8
9
10
11
12
13
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
int registryId = System.identityHashCode(registry);
if (this.registriesPostProcessed.contains(registryId)) {
throw new IllegalStateException(
"postProcessBeanDefinitionRegistry already called on this post-processor against " + registry);
}
if (this.factoriesPostProcessed.contains(registryId)) {
throw new IllegalStateException(
"postProcessBeanFactory already called on this post-processor against " + registry);
}
this.registriesPostProcessed.add(registryId);
processConfigBeanDefinitions(registry);
}

下面对 processConfigBeanDefinitions 中的方法一步一步看:

使用processConfigBeanDefinitions解析注册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
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
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
// 获得所有的已经注册的Bean,其中包括Spring内置的Processor,
// 当然也包括自己写的@Configuration类
String[] candidateNames = registry.getBeanDefinitionNames();
// 对每个候选的Bean进行筛选
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);
}
}
else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
// 如果是使用AnnotatedBeanDefinition定义(@Configuration),如果是
// 设置一些属性如根据proxyBeanMethods指定用来避免运行时创建CGLIB的子类等等。。
configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
}
}

// Return immediately if no @Configuration classes were found
if (configCandidates.isEmpty()) {
return;
}

// 对给定的Order(@Order)进行排序
configCandidates.sort((bd1, bd2) -> {
int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
return Integer.compare(i1, i2);
});

//设置Bean的名称的生成策略
SingletonBeanRegistry sbr = null;
if (registry instanceof SingletonBeanRegistry) {
sbr = (SingletonBeanRegistry) registry;
if (!this.localBeanNameGeneratorSet) {
// 如果没有设置默认的名称生成策略
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();
}

// 解析所有的@Configuration类,首先先声明出一个解析器
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 {
// 使用解析器对所有的配置类进行解析,在解析的过程中
// 完成对Bean的注册
parser.parse(candidates);
// 进行验证
parser.validate();
// 通过parser处理得到了配置文件下的Bean
Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
// 移除所有的已经解析过的Bean'
configClasses.removeAll(alreadyParsed);

// Read the model and create bean definitions based on its content
if (this.reader == null) {
this.reader = new ConfigurationClassBeanDefinitionReader(
registry, this.sourceExtractor, this.resourceLoader, this.environment,
this.importBeanNameGenerator, parser.getImportRegistry());
}
this.reader.loadBeanDefinitions(configClasses);
// 对所有已经解析的Bean进行标记
alreadyParsed.addAll(configClasses);

candidates.clear();
// 如果registry中的Bean定义数量 大于 candidateNames 的数量,说明在Bean注册过程中
// 产生了其他Bean,重复过程注册这个Bean
if (registry.getBeanDefinitionCount() > candidateNames.length) {
// 。。。。。省略
}
}
while (!candidates.isEmpty());

// 将ImportRegistry注册为Bean,以支持ImportAware @Configuration类
if (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
}
}

上述代码完成了的过程大致分为这几步

  1. 找出Config配置类,包括使用@Configuration注解标注的配置类
  2. 根据@Order进行进行顺序的调整
  3. 解析所有的@Configuration内的Bean,完成对配置类中所有 Bean的注册
  4. 验证并进行标记Bean已经被解析注册

其中最重要的就是第3步,需要找出Bean,并进行注册

parse方法解析并完成注册Bean的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public void parse(Set<BeanDefinitionHolder> configCandidates) {
for (BeanDefinitionHolder holder : configCandidates) {
// 获得配置类的定义信息
BeanDefinition bd = holder.getBeanDefinition();
try {
// 如果是使用注解方式配置类
if (bd instanceof AnnotatedBeanDefinition) {
parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
}
// else if ... if .... etc
}
// etc ....
}
this.deferredImportSelectorHandler.process();
}

protected final void parse(AnnotationMetadata metadata, String beanName) throws IOException {
processConfigurationClass(new ConfigurationClass(metadata, beanName));
}

如果使用注解方式进行配置类的配置的情况,最后会调用 processConfigurationClass 方法进行处理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
// 根据Contional注解来判断是否需要跳过配置类的处理
// 如果需要跳过,则直接进行return
if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
return;
}

ConfigurationClass existingClass = this.configurationClasses.get(configClass);
if (existingClass != null) {
//如果已经存在的情况
}

// 递归处理配置类及其超类层次结构
SourceClass sourceClass = asSourceClass(configClass);
do {
sourceClass = doProcessConfigurationClass(configClass, sourceClass);
}
while (sourceClass != null);
this.configurationClasses.put(configClass, configClass);
}

最后会递归使用 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
protected final SourceClass doProcessConfigurationClass(
ConfigurationClass configClass, SourceClass sourceClass)
throws IOException {
//如果在配置文件上有标注Component注解,则会递归处理任何成员类
if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
processMemberClasses(configClass, sourceClass);
}

// 处理 @PropertySource 注解,用于加载指定的配置文件
for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getMetadata(), PropertySources.class,
org.springframework.context.annotation.PropertySource.class)) {
// ... etc ...
}
// 处理所有的 @ComponentScan 注解
Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
if (!componentScans.isEmpty() &&
!this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
// 获取每一个 componentScans 的配置信息
for (AnnotationAttributes componentScan : componentScans) {
// 如果有 scan 类,则立即执行解析、扫描
Set<BeanDefinitionHolder> scannedBeanDefinitions =
this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
//检查扫描的定义集是否有其他配置类,并在需要时递归解析
for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
if (bdCand == null) {
bdCand = holder.getBeanDefinition();
}
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
parse(bdCand.getBeanClassName(), holder.getBeanName());
}
}
}
}

// 处理所有的 @Import 注解
processImports(configClass, sourceClass, getImports(sourceClass), true);

// Process any @ImportResource annotations

// 处理@Bean方法
Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
for (MethodMetadata methodMetadata : beanMethods) {
configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}
//处理接口上的默认方法
processInterfaces(configClass, sourceClass);
// 处理超类
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();
}
}
// 如果没有超类,处理完成。
return null;

总结在使用 doProcessConfigurationClass 方法时,大致会有这样几步:

  1. 如果标记有 @Component 注解,则会先去递归处理成员类,那么他是如何进行递归处理的呢,看主要方法的调用就能够理解:
    processMemberClasses -> processConfigurationClass -> doProcessConfigurationClass -> processMemberClasses
    每次都会递归的先处理成员类。
  2. 处理 @PropertySource 注解,作用为加载指定的配置文件
  3. 处理所有的 @ComponentScan 注解,如果配置文件中标记有 @ComponentSacn 或者 @ComponentScans 注解的话,会先去解析对应路径下的Bean,包装成 BeanDefinitionHolder 再次进行parse。
  4. 处理所有的 @Import 注解,处理所有使用Import注解引入的配置文件
  5. 处理所有的 @ImportResource 注解
  6. 处理所有 @Bean 方法,添加为 BeanMethod,解析配置文件中配置为@Bean的方法,添加到configClass中的BeanMethod中
  7. 处理接口的默认方法
  8. 按照以上逻辑进行递归的处理超类。

在方法中,可以找时间画一张图来解析这个方法真正做了写什么。[todo] 。

注册的精简过程

最后的parse方法是关键,经过以上步骤可以,在本章节需要特别注意的是 @ComponentSacn 和 处理所有的 @Bean 这两步:

在处理 @ComponentSacn 中,将直接将根据路径解析出来的Bean使用 componentScanParser.parse 方法,最终在 registerBeanDefinition() 方法中注册进去。

而在处理@Bean方法的时候,是将Bean方法包装成BeanMethod 放到 this.beanMethods 中,等待在 parse()this.reader.loadBeanDefinitions(configClasses); 中进行操作.

而在前面说的loadBeanDefinitions 中会将前面提到的 Import、ImportReource和 BeanMethod 统一进行注册。

1
2
3
4
5
6
7
8
9
if (configClass.isImported()) {
registerBeanDefinitionForImportedConfigurationClass(configClass);
}
for (BeanMethod beanMethod : configClass.getBeanMethods()) {
loadBeanDefinitionsForBeanMethod(beanMethod);
}

loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars())

在loadBeanDefinitionsForBeanMethod中,进行了对解析出来的使用@Bean标注的方法进行注册。从而完成注册Bean的主线功能。不具体进行梳理这个方法的过程,大致为构建一个BeanDefintion后,通过registerBeanDefinition方法进行注册,放到beanDefinitionMap中。

-------------本文结束感谢您的阅读-------------

本文标题:Spring的Bean的注册

文章作者:NanYin

发布时间:2019年12月20日 - 15:12

最后更新:2020年01月18日 - 09:01

原始链接:https://nanyiniu.github.io/2019/12/20/Spring%E4%BB%8E%E9%9B%B6%E5%AD%A6%E8%B5%B7%E4%B9%8B%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90%EF%BC%88%E4%B8%89%EF%BC%89/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。