@Configuration 注解源码

缘起

@Configuration注解大家都用过,一般的组合就是@Configuration+@Bean 的组合,那么它的原理是什么呢? 本文结合源码来进行分析

分析

【2】中我们已经知道了BeanDefinitionRegistryPostProcessor 接口的作用——就是为了给容器中添加新的组件. 其实 @Configuration注解就和一个BeanDefinitionRegistryPostProcessor 接口实现类有关. 这个类就是ConfigurationClassPostProcessor.

1
public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor,...

可见,该类用于向容器中添加新的组件. 那么该类的bean定义是什么时候注册到ioc容器(即beanFactory)中去的呢?

调用栈是

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
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
-->
public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
this();
public AnnotationConfigApplicationContext() {
this.reader = new AnnotatedBeanDefinitionReader(this);
-->
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
...
AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry); // registry就是ioc容器——beanFactory
-->
跟了几步
org.springframework.context.annotation.AnnotationConfigUtils.registerAnnotationConfigProcessors(BeanDefinitionRegistry, Object) {
...
if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
}
...
}
--> org.springframework.context.annotation.AnnotationConfigUtils.registerPostProcessor(BeanDefinitionRegistry, RootBeanDefinition, String) {
...
registry.registerBeanDefinition(beanName, definition);
...
}
-->
org.springframework.beans.factory.support.DefaultListableBeanFactory.registerBeanDefinition(String, BeanDefinition) 注册到 beanDefinitionNames中去.

既然注册了,那么这个ConfigurationClassPostProcessor作为BeanDefinitionRegistryPostProcessor 接口的实现类什么时候起作用呢?

其实 【2】中也说了(【2】中搜索”第八行的源码如下”), 就在【2】中的源码1的第六行起作用.

wait,wait,wait~ 我们刚刚应该只是说了已经向ioc容器中写了ConfigurationClassPostProcessor的bean定义吧? 怎么着,这个ConfigurationClassPostProcessor被实例化了? 在哪里被实例化的呢?就在【2】的源码1的第四行,因为调用了getBean方法, 这里就会一路 doGetBean、createBean、doCreateBean 这样最终导致实例化.

既然实例化了ConfigurationClassPostProcessor, 我们来到它的postProcessBeanDefinitionRegistry接口方法(这是作为BeanDefinitionRegistryPostProcessor接口必须要实现的方法,至于是怎么到来的,【2】中搜索”debug可以发现,调用栈如下”, 就知道是从refresh方法中的invokeBeanFactoryPostProcessors(beanFactory)发起的对ConfigurationClassPostProcessor作为BeanDefinitionRegistryPostProcessor 接口 的调用, 而这里ConfigurationClassPostProcessor的实例化根据上面知道是从refresh中的this() 进行的. 所以,清楚顺序了吗? )

org.springframework.context.annotation.ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry(BeanDefinitionRegistry)

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

processConfigBeanDefinitions(registry);
}

​ 源码1

跟进第14行

org.springframework.context.annotation.ConfigurationClassPostProcessor.processConfigBeanDefinitions(BeanDefinitionRegistry)

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
List<BeanDefinitionHolder> configCandidates = new ArrayList<BeanDefinitionHolder>();
String[] candidateNames = registry.getBeanDefinitionNames();

for (String beanName : candidateNames) {
BeanDefinition beanDef = registry.getBeanDefinition(beanName);
if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) ||
ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {
if (logger.isDebugEnabled()) {
logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
}
}
else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
}
}
...

// Parse each @Configuration class
ConfigurationClassParser parser = new ConfigurationClassParser(
this.metadataReaderFactory, this.problemReporter, this.environment,
this.resourceLoader, this.componentScanBeanNameGenerator, registry);
Set<BeanDefinitionHolder> candidates = new LinkedHashSet<BeanDefinitionHolder>(configCandidates);
...
parser.parse(candidates); // 这里进行的是 @Import注解的解析,这个在【3】中详解
parser.validate();
// 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);
...

​ 源码2

其中第13行的configClasses就是MainConfig. 跟进源码2的32行

org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.loadBeanDefinitionsForConfigurationClass(ConfigurationClass, TrackedConditionEvaluator)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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;
}

if (configClass.isImported()) {
registerBeanDefinitionForImportedConfigurationClass(configClass);
}
for (BeanMethod beanMethod : configClass.getBeanMethods()) {
loadBeanDefinitionsForBeanMethod(beanMethod);
}
loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
}

​ 源码3

注意,源码3的17行,这是在解析@Bean注解的组件, 其实下面的过程就在【1】中说过了. loadBeanDefinitionsForBeanMethod方法的源码如下

1
2
3
4
private void loadBeanDefinitionsForBeanMethod(BeanMethod beanMethod) {
...
this.registry.registerBeanDefinition(beanName, beanDefToRegister);
}

​ 源码4

后面在【1】中就说过了. 这样 @Configuration+@Bean的组合就分析完了。

完了? wait~wait~wait!至今为止,我们都不晓得 @Configuration注解用在哪里呢!!!

跟进源码2的第25行,

org.springframework.context.annotation.ConfigurationClassParser.validate()

1
2
3
4
5
public void validate() {
for (ConfigurationClass configClass : this.configurationClasses.keySet()) {
configClass.validate(this.problemReporter);
}
}

​ 源码5

源码5的configurationClasses到底是个什么东西会在【3】中详述

跟进源码5的第3行

org.springframework.context.annotation.ConfigurationClass.validate(ProblemReporter)

1
2
3
4
5
6
7
8
9
10
11
12
public void validate(ProblemReporter problemReporter) {
// A configuration class may not be final (CGLIB limitation)
if (getMetadata().isAnnotated(Configuration.class.getName())) {
if (getMetadata().isFinal()) {
problemReporter.error(new FinalConfigurationProblem());
}
}

for (BeanMethod beanMethod : this.beanMethods) {
beanMethod.validate(problemReporter);
}
}

​ 源码6

看到了第3行没有? ok啦~

参考

【1】https://yfsyfs.github.io/2019/06/17/Bean-%E6%98%AF%E5%A6%82%E4%BD%95%E5%B0%86bean%E6%B3%A8%E5%85%A5%E5%88%B0ioc%E5%AE%B9%E5%99%A8%E4%B8%AD%E5%8E%BB%E7%9A%84/

【2】https://yfsyfs.github.io/2019/06/23/BeanDefinitionRegistryPostProcessor-%E5%8E%9F%E7%90%86%E8%AF%B4%E6%98%8E/

【3】https://yfsyfs.github.io/2019/06/25/Import%E6%B3%A8%E8%A7%A3%E7%9A%84%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90/