抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

SpringIOC-Configuration注解的支持

前言

​ 前几篇已经完成了obtainFreshBeanFactory方法的调用,已经完成了XML的解析以及注册就完成了,但是如果注册的bean不符合需要呢,需要一些处理,对注册的BeanDefinition做一些变更怎么办呢,这就要用到今天讲的BeanFactor后置处理器,是invokeBeanFactoryPostProcessors方法,他会在注册完成BeanDefinition紧接着就会调用该方法,完成注册的BeanDefinition的修改操作,但是在invokeBeanFactoryPostProcessors方法中有一个很重要的部分就是对@Configuration这个注解的支持

ConfigurationClassPostProcessor

Spring中最!最!最!重要的后置处理器!没有之一!!!

作用

  1. ConfigurationClassPostProcessor是一个BeanFactory的后置处理器,因此它的主要功能是参与BeanFactory的建造,在这个类中,会解析加了@Configuration的配置类,还会解析@ComponentScan、@ComponentScans注解扫描的包,以及解析@Import,@Bean,@ImportResource等注解。
  2. ConfigurationClassPostProcessor 实现了 BeanDefinitionRegistryPostProcessor 接口,而 BeanDefinitionRegistryPostProcessor 接口继承了 BeanFactoryPostProcessor 接口,所以 ConfigurationClassPostProcessor 中需要重写 postProcessBeanDefinitionRegistry() 方法和 postProcessBeanFactory() 方法。而ConfigurationClassPostProcessor类的作用就是通过这两个方法去实现的。

大致处理流程

  1. 在 bean factory 中查找已经添加的配置类
  2. 对上一步的configClass进行排序。
  3. 利用 ConfigurationClassParser 解析配置类(解析该配置类上的其他注解)。
    1. 调用 doProcessConfigurationClass 方法解析配置类
    2. 如果成员类也是配置类,则先解析成员类
    3. 处理配置类上的显示或隐式的 @PropertySources 和 @PropertySource 注解
    4. 处理配置类上显示或隐式的 @ComponentScans 和 @ComponentScan 注解,解析与其相关的配置类
    5. 处理 @Import 注解,查找配置类上显示和隐式的 @Import 注解,保存注解的 value 值
    6. 处理 @ImportResource 注解
    7. 为配置类添加带 @Bean 注解的方法
    8. 查找接口中带 @Bean 注解的方法
    9. 如果父类也是配置类,则解析父类
    10. 处理 DeferredImportSelector
  4. 将上一步解析出来的新配置类通过 loadBeanDefinitions 添加到 bean factory 中。
  5. 如果 bean factory 中有还没有解析的配置类,重复第3步。

  

​ 有 @Configuration、@Import 、 @Component、@ComponentScan 以及 @ImportResource 这几个注解的类都是配置类,都会对其进行上面的处理。除了 @Configuration 注解只标识为配置类之外,另外几个注解都有各自的作用,在配置类处理过程中会根据这些注解的参数进行处理。

代码分析

接着上一节的内容分析

invokeBeanFactoryPostProcessors->invokeBeanFactoryPostProcessors->postProcessBeanDefinitionRegistry

postProcessBeanDefinitionRegistry

来到ConfigurationClassPostProcessor类

主要完成初始化完成BeanDefinition后调用该接口 进行已注册的BeanDefinition的增删改查

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
* 初始化完成BeanDefinition后调用该接口 进行已注册的BeanDefinition的增删改查
*/
@Override
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);
//进行处理BeanDefinition
processConfigBeanDefinitions(registry);
}
processConfigBeanDefinitions

处理已经注册的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
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
/**
* 处理已经注册的BeanDefinition
*/
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
//从registry中获取所有注册的DefinitionNames
String[] candidateNames = registry.getBeanDefinitionNames();
//进行遍历所有注册的DefinitionNames
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);
}
//判断是否有@Configuration,@Component,@ComponentScan,@Import,@ImportResource,@Bean注解
} else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
//有的话创建BeanDefinitionHolder并加入configCandidates
configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
}
}

// Return immediately if no @Configuration classes were found
//如果configCandidates为空直接返回
if (configCandidates.isEmpty()) {
return;
}

// Sort by previously determined @Order value, if applicable
//进行排序
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实现了SingletonBeanRegistry接口
if (registry instanceof SingletonBeanRegistry) {
sbr = (SingletonBeanRegistry) registry;
if (!this.localBeanNameGeneratorSet) {
//获取internalConfigurationBeanNameGenerator
BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(
AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR);
if (generator != null) {
//赋值给全局的componentScanBeanNameGenerator,importBeanNameGenerator为internalConfigurationBeanNameGenerator的解析器
this.componentScanBeanNameGenerator = generator;
this.importBeanNameGenerator = generator;
}
}
}

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

// Parse each @Configuration class
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 {
//解析刚刚注册的包含@Configuration,@Component,@ComponentScan,@Import,@ImportResource,@Bean注解的BeanDefinition
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
if (this.reader == null) {
this.reader = new ConfigurationClassBeanDefinitionReader(
registry, this.sourceExtractor, this.resourceLoader, this.environment,
this.importBeanNameGenerator, parser.getImportRegistry());
}
//设置BeanDefinition的属性值,重点看具体执行 @Import,@ImportSource,@Bean的逻辑
this.reader.loadBeanDefinitions(configClasses);
//将注册完成的configClasses加入到alreadyParsed
alreadyParsed.addAll(configClasses);
//清除集合
candidates.clear();
if (registry.getBeanDefinitionCount() > candidateNames.length) {
String[] newCandidateNames = registry.getBeanDefinitionNames();
Set<String> oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames));
Set<String> alreadyParsedClasses = new HashSet<>();
for (ConfigurationClass configurationClass : alreadyParsed) {
alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
}
for (String candidateName : newCandidateNames) {
if (!oldCandidateNames.contains(candidateName)) {
BeanDefinition bd = registry.getBeanDefinition(candidateName);
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
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. 从registry中获取所有注册的DefinitionNames
  2. 进行遍历所有注册的DefinitionNames
  3. 判断是否有@Configuration,@Component,@ComponentScan,@Import,@ImportResource,@Bean注解
  4. 有的话创建BeanDefinitionHolder并加入configCandidates
  5. 对configCandidates进行排序
  6. 创建注解解析器
  7. 解析刚刚注册的包含@Configuration,@Component,@ComponentScan,@Import,@ImportResource,@Bean注解的BeanDefinition
  8. 调用loadBeanDefinitions,设置BeanDefinition的属性值,重点看具体执行 @Import,@ImportSource,@Bean的逻辑

processConfigBeanDefinitions流程分析

checkConfigurationClassCandidate

判断是否有@Configuration,@Component,@ComponentScan,@Import,@ImportResource,@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
/**
* 判断是否有@Configuration,@Component@ComponentScan@Import@ImportResource@Bean注解
*/
public static boolean checkConfigurationClassCandidate(
BeanDefinition beanDef, MetadataReaderFactory metadataReaderFactory) {
//拿到BeanDefinition的className
String className = beanDef.getBeanClassName();
if (className == null || beanDef.getFactoryMethodName() != null) {
return false;
}

AnnotationMetadata metadata;
//如果BeanDefinition是AnnotatedBeanDefinition类型的并且传入的className和Metadata中的className一致
if (beanDef instanceof AnnotatedBeanDefinition &&
className.equals(((AnnotatedBeanDefinition) beanDef).getMetadata().getClassName())) {
// Can reuse the pre-parsed metadata from the given BeanDefinition...
//拿到Metadata
metadata = ((AnnotatedBeanDefinition) beanDef).getMetadata();
} else if (beanDef instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) beanDef).hasBeanClass()) {
// Check already loaded Class if present...
// since we possibly can't even load the class file for this Class.
Class<?> beanClass = ((AbstractBeanDefinition) beanDef).getBeanClass();
if (BeanFactoryPostProcessor.class.isAssignableFrom(beanClass) ||
BeanPostProcessor.class.isAssignableFrom(beanClass) ||
AopInfrastructureBean.class.isAssignableFrom(beanClass) ||
EventListenerFactory.class.isAssignableFrom(beanClass)) {
return false;
}
//拿到Metadata
metadata = AnnotationMetadata.introspect(beanClass);
} else {
try {
MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(className);
//拿到Metadata
metadata = metadataReader.getAnnotationMetadata();
} catch (IOException ex) {
if (logger.isDebugEnabled()) {
logger.debug("Could not find class file for introspecting configuration annotations: " +
className, ex);
}
return false;
}
}
//如果metadata中有@Configuration注解
Map<String, Object> config = metadata.getAnnotationAttributes(Configuration.class.getName());
if (config != null && !Boolean.FALSE.equals(config.get("proxyBeanMethods"))) {
beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL);
//config不为空并且检查metadata是否有一下注解@Component,@ComponentScan,@Import,@ImportResource,@Bean
} else if (config != null || isConfigurationCandidate(metadata)) {
beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE);
} else {
return false;
}

该方法主要是拿到metadata,并从metadata中获取@Configuration注解的信息然后调用isConfigurationCandidate进行判断

isConfigurationCandidate

检查metadata是否有一下注解@Component,@ComponentScan,@Import,@ImportResource,@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
private static final Set<String> candidateIndicators = new HashSet<>(8);

static {
candidateIndicators.add(Component.class.getName());
candidateIndicators.add(ComponentScan.class.getName());
candidateIndicators.add(Import.class.getName());
candidateIndicators.add(ImportResource.class.getName());
}

/**
* 检查metadata是否有一下注解@Component@ComponentScan@Import@ImportResource@Bean
*/
public static boolean isConfigurationCandidate(AnnotationMetadata metadata) {
// Do not consider an interface or an annotation...
if (metadata.isInterface()) {
return false;
}

// Any of the typical annotations found?
//检查metadata是否有@Component,@ComponentScan,@Import,@ImportResource中的一个
//有的话就返回true
for (String indicator : candidateIndicators) {
if (metadata.isAnnotated(indicator)) {
return true;
}
}

// Finally, let's look for @Bean methods...
try {
//检查是方法中是否有@Bean的注解
return metadata.hasAnnotatedMethods(Bean.class.getName());
} catch (Throwable ex) {
if (logger.isDebugEnabled()) {
logger.debug("Failed to introspect @Bean methods on class [" + metadata.getClassName() + "]: " + ex);
}
return false;
}
}

注解解析流程

解析刚刚注册的包含@Configuration,@Component,@ComponentScan,@Import,@ImportResource,@Bean注解的BeanDefinition

1
parser.parse(candidates);
parse

解析刚刚创建的BeanDefinitionHolder

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
/**
* 解析BeanDefinitionHolder
*/
public void parse(Set<BeanDefinitionHolder> configCandidates) {
for (BeanDefinitionHolder holder : configCandidates) {
BeanDefinition bd = holder.getBeanDefinition();
try {
//如果BeanDefinitionHolder实现了AnnotatedBeanDefinition
if (bd instanceof AnnotatedBeanDefinition) {
parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
//如果BeanDefinitionHolder实现了AbstractBeanDefinition并且有BeanClass
} 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();
}
parse

封装成ConfigurationClass进行解析,下面是对这几个parse重载

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
* 使用Configuration解析
*
*/
protected final void parse(AnnotationMetadata metadata, String beanName) throws IOException {
//解析ConfigurationClass
processConfigurationClass(new ConfigurationClass(metadata, beanName));
}

protected final void parse(Class<?> clazz, String beanName) throws IOException {
processConfigurationClass(new ConfigurationClass(clazz, beanName));
}

protected final void parse(@Nullable String className, String beanName) throws IOException {
Assert.notNull(className, "No bean class name for configuration class bean definition");
MetadataReader reader = this.metadataReaderFactory.getMetadataReader(className);
processConfigurationClass(new ConfigurationClass(reader, beanName));
}
processConfigurationClass

解析ConfigurationClass

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
/**
* 解析ConfigurationClass
*/
protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
return;
}
//检查configurationClasses是否已经存在
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.
//再次将configClass封装为SourceClass
SourceClass sourceClass = asSourceClass(configClass);
do {
//解析ConfigurationClass
sourceClass = doProcessConfigurationClass(configClass, sourceClass);
}
while (sourceClass != null);

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

真实开始解析ConfigurationClass

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
/**
* multiple times as relevant sources are discovered.
* 解析ConfigurationClass
*
*/
@Nullable
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
throws IOException {
//检查是否包含@Component注解
if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
// Recursively process any member (nested) classes first
//处理@Component注解
processMemberClasses(configClass, sourceClass);
}

// Process any @PropertySource annotations
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");
}
}

//对@ComponentScan注解的支撑
// Process any @ComponentScan annotations
//搜集@ComponentScan注解
Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
//搜集的@componentScans不为空
if (!componentScans.isEmpty() &&
!this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
//遍历所有包含@ComponentScan注解的类
for (AnnotationAttributes componentScan : componentScans) {
// The config class is annotated with @ComponentScan -> perform the scan immediately
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)) {
//解析@ComponentScan,对@ComponentScan注解的支撑
parse(bdCand.getBeanClassName(), holder.getBeanName());
}
}
}
}

// Process any @Import annotations
//对@Import注解的支撑
processImports(configClass, sourceClass, getImports(sourceClass), true);

// Process any @ImportResource annotations
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
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;
}
小结

这个方法也比较大梳理下流程

  1. 检查是否包含@Component注解,包含的话调用processMemberClasses处理@ComCponent注解
  2. 对@PropertySources注解的支持,不重要用处不大这里略过
  3. 对@ComponentScan注解的支撑
    1. 搜集@ComponentScan注解
    2. 遍历所有包含@ComponentScan注解的类
    3. 解析@ComponentScan注解,扫描注解将包含有@ComCponent注解的类包装成BeanDefinitionHolder返回
    4. 遍历所有的BeanDefinitionHolder
    5. 检查是有@Configuration注解有的话重新调用parse方法解析循环调用

处理@Component注解

1
2
//处理@Component注解
processMemberClasses(configClass, sourceClass);
processMemberClasses

处理@Component注解

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注解
*/
private void processMemberClasses(ConfigurationClass configClass, SourceClass sourceClass) throws IOException {
//获取所有SourceClass的集合
Collection<SourceClass> memberClasses = sourceClass.getMemberClasses();
if (!memberClasses.isEmpty()) {
List<SourceClass> candidates = new ArrayList<>(memberClasses.size());
//遍历SourceClass
for (SourceClass memberClass : memberClasses) {
//检查metadata是否有一下注解@Component,@ComponentScan,@Import,@ImportResource,@Bean
if (ConfigurationClassUtils.isConfigurationCandidate(memberClass.getMetadata()) &&
!memberClass.getMetadata().getClassName().equals(configClass.getMetadata().getClassName())) {
//将符合要求的SourceClass加入到candidates
candidates.add(memberClass);
}
}
//排序
OrderComparator.sort(candidates);
//遍历SourceClass
for (SourceClass candidate : candidates) {
if (this.importStack.contains(configClass)) {
this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
} else {
this.importStack.push(configClass);
try {
//调用processConfigurationClass来解析
processConfigurationClass(candidate.asConfigClass(configClass));
} finally {
this.importStack.pop();
}
}
}
}
}

这个方法主要处理@Component注解,遍历遍历所有的SourceClass,再次调用processConfigurationClass

解析@ComponentScan注解

解析@ComponentScan注解,扫描注解将包含有@ComCponent注解的类包装成BeanDefinitionHolder返回

1
Set<BeanDefinitionHolder> scannedBeanDefinitions =this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
parse

解析@ComponentScan注解,扫描注解将包含有@ComCponent注解的类包装成BeanDefinitionHolder返回

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
/**
* 解析@ComponentScan注解,扫描注解将包含有@ComCponent注解的类包装成BeanDefinitionHolder返回
*/
public Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan, final String declaringClass) {
//创建ClassPathBeanDefinitionScanner扫描器
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(this.registry,
componentScan.getBoolean("useDefaultFilters"), this.environment, this.resourceLoader);
//获取nameGenerator属性
Class<? extends BeanNameGenerator> generatorClass = componentScan.getClass("nameGenerator");
boolean useInheritedGenerator = (BeanNameGenerator.class == generatorClass);
scanner.setBeanNameGenerator(useInheritedGenerator ? this.beanNameGenerator :
BeanUtils.instantiateClass(generatorClass));
//获取scopedProxy属性
ScopedProxyMode scopedProxyMode = componentScan.getEnum("scopedProxy");
if (scopedProxyMode != ScopedProxyMode.DEFAULT) {
scanner.setScopedProxyMode(scopedProxyMode);
} else {
Class<? extends ScopeMetadataResolver> resolverClass = componentScan.getClass("scopeResolver");
scanner.setScopeMetadataResolver(BeanUtils.instantiateClass(resolverClass));
}
//获取并设置resourcePattern属性
scanner.setResourcePattern(componentScan.getString("resourcePattern"));
//获取并设置includeFilters属性
for (AnnotationAttributes filter : componentScan.getAnnotationArray("includeFilters")) {
for (TypeFilter typeFilter : typeFiltersFor(filter)) {
scanner.addIncludeFilter(typeFilter);
}
}
//获取并设置excludeFilters属性
for (AnnotationAttributes filter : componentScan.getAnnotationArray("excludeFilters")) {
for (TypeFilter typeFilter : typeFiltersFor(filter)) {
scanner.addExcludeFilter(typeFilter);
}
}
//获取并设置是否懒加载
boolean lazyInit = componentScan.getBoolean("lazyInit");
if (lazyInit) {
scanner.getBeanDefinitionDefaults().setLazyInit(true);
}

Set<String> basePackages = new LinkedHashSet<>();
//获取并设置basePackages
String[] basePackagesArray = componentScan.getStringArray("basePackages");
for (String pkg : basePackagesArray) {
String[] tokenized = StringUtils.tokenizeToStringArray(this.environment.resolvePlaceholders(pkg),
ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
Collections.addAll(basePackages, tokenized);
}
//获取并设置basePackageClasses
for (Class<?> clazz : componentScan.getClassArray("basePackageClasses")) {
basePackages.add(ClassUtils.getPackageName(clazz));
}
if (basePackages.isEmpty()) {
basePackages.add(ClassUtils.getPackageName(declaringClass));
}
//设置排除选项
scanner.addExcludeFilter(new AbstractTypeHierarchyTraversingFilter(false, false) {
@Override
protected boolean matchClassName(String className) {
return declaringClass.equals(className);
}
});
//开始扫描
return scanner.doScan(StringUtils.toStringArray(basePackages));
}

这个类和前面讲到的对配置文件的<context:component-scan base-package=”com.test”/>的注解类似

最终会调用scanner.doScan来到真正的开始进行扫描详细的参见xml的解析形式

BeanDefinition的属性值属性的完善

因为刚刚扫描的BeanDefinition只是简单的封装,具体可以参考xml的解析形式,还需要调用loadBeanDefinitions对BeanDefinition的属性进行完善

loadBeanDefinitions

设置BeanDefinition的属性值,重点看具体执行 @Import,@ImportSource,@Bean的逻辑

1
2
3
4
5
6
7
8
9
10
11
/**
* 设置BeanDefinition的属性值,重点看具体执行 @Import,@ImportSource,@Bean的逻辑
*/
public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) {
TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator();
//遍历所有的ConfigurationClass
for (ConfigurationClass configClass : configurationModel) {
//继续loadloadBeanDefinition
loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);
}
}
loadBeanDefinitionsForConfigurationClass

设置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
/**
* 设置BeanDefinition的属性值
*/
private void loadBeanDefinitionsForConfigurationClass(
ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) {

if (trackedConditionEvaluator.shouldSkip(configClass)) {
String beanName = configClass.getBeanName();
if (StringUtils.hasLength(beanName) && this.registry.containsBeanDefinition(beanName)) {
this.registry.removeBeanDefinition(beanName);
}
this.importRegistry.removeImportingClass(configClass.getMetadata().getClassName());
return;
}
//如果是是@Import的注解
if (configClass.isImported()) {
//注册BeanDefinition
registerBeanDefinitionForImportedConfigurationClass(configClass);
}
//如果是@Bean的注解
for (BeanMethod beanMethod : configClass.getBeanMethods()) {
//设置@Bean的注解的处理
loadBeanDefinitionsForBeanMethod(beanMethod);
}
//对@ImportedResource的支持
loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
}

对功能注解的支持

对@Importe,@Bean,@ImportedResource注解的处理

registerBeanDefinitionForImportedConfigurationClass

注册@Importe的类到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
private void registerBeanDefinitionForImportedConfigurationClass(ConfigurationClass configClass) {
//获取metadata
AnnotationMetadata metadata = configClass.getMetadata();
//将ConfigurationClass封装成BeanDefinition
AnnotatedGenericBeanDefinition configBeanDef = new AnnotatedGenericBeanDefinition(metadata);
//获取并设置作用域
ScopeMetadata scopeMetadata = scopeMetadataResolver.resolveScopeMetadata(configBeanDef);
configBeanDef.setScope(scopeMetadata.getScopeName());
//获取注解中的bean的name
String configBeanName = this.importBeanNameGenerator.generateBeanName(configBeanDef, this.registry);
//将公共注解设置进BeanDefinition中
AnnotationConfigUtils.processCommonDefinitionAnnotations(configBeanDef, metadata);
//封装成BeanDefinitionHolder
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(configBeanDef, configBeanName);

definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
//进行BeanDefinition的注册
this.registry.registerBeanDefinition(definitionHolder.getBeanName(), definitionHolder.getBeanDefinition());
//设置bean的名称
configClass.setBeanName(configBeanName);

if (logger.isTraceEnabled()) {
logger.trace("Registered bean definition for imported class '" + configBeanName + "'");
}
}
小结

这个个类对于理解SpringBoot有很大帮助

Springboot的各种自定义注解最终都需要@Importe的支持

@Importe就是将类包装成BeanDefinition进行注册

完成BeanDefinition的各种参数设置后,调用registerBeanDefinition方法完成registerBeanDefinition的注册

loadBeanDefinitionsForBeanMethod

对@Bean的注解的支持

对@Bean的注解的方法的处理方式是

将@Bean 转换为 工厂方法的处理方式将@bean的注解方法加入到BeanDefinition的FactoryMethodName

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
/**

* 对@Bean的注解的方法的处理
* 将@Bean 转换为 工厂方法的处理方式将@bean的注解方法加入到BeanDefinition的FactoryMethodName
*/
@SuppressWarnings("deprecation") // for RequiredAnnotationBeanPostProcessor.SKIP_REQUIRED_CHECK_ATTRIBUTE
private void loadBeanDefinitionsForBeanMethod(BeanMethod beanMethod) {
//获取bean的class
ConfigurationClass configClass = beanMethod.getConfigurationClass();
//获取metadata
MethodMetadata metadata = beanMethod.getMetadata();
//获取方法名称
String methodName = metadata.getMethodName();

// Do we need to mark the bean as skipped by its condition?
if (this.conditionEvaluator.shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN)) {
configClass.skippedBeanMethods.add(methodName);
return;
}
if (configClass.skippedBeanMethods.contains(methodName)) {
return;
}
//获取@Bean的注解的bean
AnnotationAttributes bean = AnnotationConfigUtils.attributesFor(metadata, Bean.class);
Assert.state(bean != null, "No @Bean annotation attributes");

// Consider name and any aliases
//获取name的属性
List<String> names = new ArrayList<>(Arrays.asList(bean.getStringArray("name")));
String beanName = (!names.isEmpty() ? names.remove(0) : methodName);

// Register aliases even when overridden
//注册别名
for (String alias : names) {
this.registry.registerAlias(beanName, alias);
}

// Has this effectively been overridden before (e.g. via XML)?
//bean是否已经注册
if (isOverriddenByExistingDefinition(beanMethod, beanName)) {
if (beanName.equals(beanMethod.getConfigurationClass().getBeanName())) {
throw new BeanDefinitionStoreException(beanMethod.getConfigurationClass().getResource().getDescription(),
beanName, "Bean name derived from @Bean method '" + beanMethod.getMetadata().getMethodName() +
"' clashes with bean name for containing configuration class; please make those names unique!");
}
return;
}
//创建BeanDefinition
ConfigurationClassBeanDefinition beanDef = new ConfigurationClassBeanDefinition(configClass, metadata);
//设置Resource
beanDef.setResource(configClass.getResource());
//设置Source
beanDef.setSource(this.sourceExtractor.extractSource(metadata, configClass.getResource()));
//如果该类是静态的
if (metadata.isStatic()) {
// static @Bean method
//设置@bean的class
if (configClass.getMetadata() instanceof StandardAnnotationMetadata) {
//设置bean的class
beanDef.setBeanClass(((StandardAnnotationMetadata) configClass.getMetadata()).getIntrospectedClass());
} else {
//设置bean的className
beanDef.setBeanClassName(configClass.getMetadata().getClassName());
}
//设置唯一的bean的FactoryMethodName
beanDef.setUniqueFactoryMethodName(methodName);
} else {
// instance @Bean method
//不是静态的就设置工厂bean的name
beanDef.setFactoryBeanName(configClass.getBeanName());
//设置唯一的bean的FactoryMethodName
beanDef.setUniqueFactoryMethodName(methodName);
}

if (metadata instanceof StandardMethodMetadata) {
beanDef.setResolvedFactoryMethod(((StandardMethodMetadata) metadata).getIntrospectedMethod());
}
//设置自动注入类型
beanDef.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR);
beanDef.setAttribute(org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor.
SKIP_REQUIRED_CHECK_ATTRIBUTE, Boolean.TRUE);

//将公共注解设置进BeanDefinition中
AnnotationConfigUtils.processCommonDefinitionAnnotations(beanDef, metadata);

Autowire autowire = bean.getEnum("autowire");
if (autowire.isAutowire()) {
beanDef.setAutowireMode(autowire.value());
}

boolean autowireCandidate = bean.getBoolean("autowireCandidate");
if (!autowireCandidate) {
beanDef.setAutowireCandidate(false);
}

String initMethodName = bean.getString("initMethod");
if (StringUtils.hasText(initMethodName)) {
beanDef.setInitMethodName(initMethodName);
}

String destroyMethodName = bean.getString("destroyMethod");
beanDef.setDestroyMethodName(destroyMethodName);

// Consider scoping
ScopedProxyMode proxyMode = ScopedProxyMode.NO;
AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(metadata, Scope.class);
if (attributes != null) {
beanDef.setScope(attributes.getString("value"));
proxyMode = attributes.getEnum("proxyMode");
if (proxyMode == ScopedProxyMode.DEFAULT) {
proxyMode = ScopedProxyMode.NO;
}
}

// Replace the original bean definition with the target one, if necessary
BeanDefinition beanDefToRegister = beanDef;
if (proxyMode != ScopedProxyMode.NO) {
BeanDefinitionHolder proxyDef = ScopedProxyCreator.createScopedProxy(
new BeanDefinitionHolder(beanDef, beanName), this.registry,
proxyMode == ScopedProxyMode.TARGET_CLASS);
beanDefToRegister = new ConfigurationClassBeanDefinition(
(RootBeanDefinition) proxyDef.getBeanDefinition(), configClass, metadata);
}

if (logger.isTraceEnabled()) {
logger.trace(String.format("Registering bean definition for @Bean method %s.%s()",
configClass.getMetadata().getClassName(), beanName));
}
this.registry.registerBeanDefinition(beanName, beanDefToRegister);
}

小结

对于@Bean注解最终也是将类转换成BeanDefinition进行注册,这里要注意一下,如果一个类有多个@Bean他会注册多个BeanDefinition而不只是一个

@Bean在BeanDefinition注册中最终会转换成工厂类和方式的像是注册

如果是静态方法就只注册静态的工厂方法

如果是普通类就把该类注册为工厂类,里面的@Bean方法注册为工厂方法

loadBeanDefinitionsFromImportedResources

对@ImportedResource的支持

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
/**
* 对@ImportedResource的支持
*/
private void loadBeanDefinitionsFromImportedResources(
Map<String, Class<? extends BeanDefinitionReader>> importedResources) {
//创建read实例化的缓存
Map<Class<?>, BeanDefinitionReader> readerInstanceCache = new HashMap<>();
//遍历importedResources创建对应的解析器
importedResources.forEach((resource, readerClass) -> {
// Default reader selection necessary?
if (BeanDefinitionReader.class == readerClass) {
//如果是groovy的文件
if (StringUtils.endsWithIgnoreCase(resource, ".groovy")) {
// When clearly asking for Groovy, that's what they'll get...
readerClass = GroovyBeanDefinitionReader.class;
} else {
//否则就是xml
// Primarily ".xml" files but for any other extension as well
readerClass = XmlBeanDefinitionReader.class;
}
}
//从缓存中获取实例化的解析器
BeanDefinitionReader reader = readerInstanceCache.get(readerClass);
if (reader == null) {
try {
// Instantiate the specified BeanDefinitionReader
//实例化解析器
reader = readerClass.getConstructor(BeanDefinitionRegistry.class).newInstance(this.registry);
// Delegate the current ResourceLoader to it if possible
//如果实现了AbstractBeanDefinitionReader接口
if (reader instanceof AbstractBeanDefinitionReader) {
AbstractBeanDefinitionReader abdr = ((AbstractBeanDefinitionReader) reader);
abdr.setResourceLoader(this.resourceLoader);
abdr.setEnvironment(this.environment);
}
//将实例化后的解析器加入缓存
readerInstanceCache.put(readerClass, reader);
} catch (Throwable ex) {
throw new IllegalStateException(
"Could not instantiate BeanDefinitionReader class [" + readerClass.getName() + "]");
}
}

// TODO SPR-6310: qualify relative path locations as done in AbstractContextLoader.modifyLocations
//进行加载资源
reader.loadBeanDefinitions(resource);
});
}

小结

​ @ImportedResource是用来导入配置文件的,处理方式是创建BeanDefinitionReader然后调用具体类型的解析器进行解析,如果是xml文件最终又会回到第一节讲的xml解析

总结

​ Spring中的@Configuration、@ComponentScan、@Import、@ImportResource、@Bean这些注解是ConfigurationClassPostProcessor来负责处理的。ConfigurationClassPostProcessor是BeanFactoryPostProcessor,在Spring注册完所有的BeanDefinition之后实例化Bean之前进行扩展。ConfigurationClassPostProcessor负责处理这些,其中根据注解的不同可能会向Spring注册新的BeanDefinition。

​ @Configuration注解描述的类本身会被注册到容器,@Bean描述的方法会被注册到容器,@ImportResource描述的配置文件会被加载会解析出BeanDefinition注册到Spring中

​ @Import导入的普通类会当做ConfigClass处理,@Import导入的ImportSelector类会执行ImportSelector#selectImports()方法,方法返回的类也作为导入进行处理@Import的逻辑,@Import导入的ImportBeanDefinitionRegistrar类,会调用它的registerBeanDefinitions()方法,由它来自定义注册BeanDefinition的逻辑。

流程总结

处理@ComponentScan注解

​ 使用ComponentScanAnnotationParser扫描basePackage下的需要解析的类(@SpringBootApplication注解也包括了@ComponentScan注解,只不过basePackages是空的,空的话会去获取当前@Configuration修饰的类所在的包[这个会在下面详细解释]),并注册到BeanFactory中(这个时候bean并没有进行实例化,而是进行了注册。具体的实例化在finishBeanFactoryInitialization方法中执行)。对于扫描出来的类,递归解析

处理@Import注解

​ 先递归找出所有的注解,然后再过滤出只有@Import注解的类,得到@Import注解的值。比如查找@SpringBootApplication注解的@Import注解数据的话,首先发现@SpringBootApplication不是一个@Import注解,然后递归调用修饰了@SpringBootApplication的注解,发现有个@EnableAutoConfiguration注解,再次递归发现被@Import(EnableAutoConfigurationImportSelector.class)修饰,还有@AutoConfigurationPackage注解修饰,再次递归@AutoConfigurationPackage注解,发现被@Import(AutoConfigurationPackages.Registrar.class)注解修饰,所以@SpringBootApplication注解对应的@Import注解有2个,分别是@Import(AutoConfigurationPackages.Registrar.class)和@Import(EnableAutoConfigurationImportSelector.class)。找出所有的@Import注解之后,开始处理逻辑:

   (1)、遍历这些@Import注解内部的属性类集合

   (2)、如果这个类是个ImportSelector接口的实现类,实例化这个ImportSelector,如果这个类也是DeferredImportSelector接口的实现类,那么加入ConfigurationClassParser的deferredImportSelectors属性中让第6步处理。否则调用ImportSelector的selectImports方法得到需要Import的类,然后对这些类递归做@Import注解的处理

   (3)、如果这个类是ImportBeanDefinitionRegistrar接口的实现类,设置到配置类ConfigurationClass的importBeanDefinitionRegistrars属性中

   (4)、其它情况下把这个类入队到ConfigurationClassParser的importStack(队列)属性中,然后把这个类当成是@Configuration注解修饰的类递归重头开始解析这个类

处理@ImportResource注解

​ 获取@ImportResource注解的locations属性,得到资源文件的地址信息。然后遍历这些资源文件并把它们添加到配置类的importedResources属性中,然后调用具体类型的解析器进行解析,如果是xml文件最终又会回到第一节讲的xml解析

处理@Bean注解

​ 获取被@Bean注解修饰的方法,然后添加到配置类的beanMethods属性中,然后再解析为BeanDefinition,根据@Bean的方法会转换成工厂方法进行BeanDefinition的注册

评论