【spring】 spring 中通过注解配置的启动过程

从源码分析 spring 如何实现注解的配置方式

前言

在 spring-boot 的启动过程中,会根据 classpath 中的类来创建对应的 AnnotationConfigApplicationContext, AnnotationConfigReactiveWebServerApplicationContext 或 AnnotationConfigServletWebServerApplicationContext 作为 application context。

这几个类都有成员 AnnotatedBeanDefinitionReader reader 和 ClassPathBeanDefinitionScanner scanner。

  • AnnotatedBeanDefinitionReader 是解析 @Configuration 注解的关键,, ConfigurationClassPostProcessor 将会在 application context refresh 的过程中扫描 @Configuration, 并从中找到 bean 配置, 注册到 beanFactory。
  • ClassPathBeanDefinitionScanner 扫描指定的类路径,找出其中 @Service, @Component (@Configuration 也是一种 @Component) 等注解修饰的类,并注册到 beanFactory。

@Configuration 解析

@Configuration 由 ConfigurationClassPostProcessor 处理。

AnnotatedBeanDefinitionReader 在它的构造方法中会将 ConfigurationClassPostProcessor 这个 BFPP 注册到 beanFactory。ConfigurationClassPostProcessor 实现了 BeanDefinitionRegistryPostProcessor,会在 application context refresh 的过程中扫描 @Configuration, 并从中找到 bean 配置, 注册到 beanFactory。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
...

// 解析 @Configuration 并注册 bean
processConfigBeanDefinitions(registry);
}

public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
...

enhanceConfigurationClasses(beanFactory);

// 注册 ImportAwareBeanPostProcessor
// ImportAwareBeanPostProcessor 实现了 SmartInstantiationAwareBeanPostProcessor 来用处理实现 ImportAware 的类
beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));
}

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
// 解析 @Configuration 并注册 bean
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {

// 从已注册的 bean 中找到 @Configuration,@Component,@ComponentScan,@Import,@ImportResource 的类放到 configCandidates
List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
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 {
// 判断是不是有 @Configuration,@Component,@ComponentScan,@Import,@ImportResource
if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
}
}
}

if (configCandidates.isEmpty()) {
return;
}

// 根据 @Order 排序
configCandidates.sort((bd1, bd2) -> {
int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
return Integer.compare(i1, i2);
});

// 看看有没有 BeanNameGenerator
SingletonBeanRegistry sbr = null;
if (registry instanceof SingletonBeanRegistry) {
sbr = (SingletonBeanRegistry) registry;
if (!this.localBeanNameGeneratorSet) {
BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(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 {
// 递归处理解析候选类
// 解析过程如下:
// 1. 计算条件 @Condition 的值,如果不满足条件就跳过解析这个类
// 2. 处理类上的 @PropertySource 注解, 加载资源文件到 PropertySource 并加到 Environment
// 3. 处理类上的 @ComponentScan 注解,用 ComponentScanAnnotationParser 扫描 @ComponentScan 配置的路径,从中找到的 @Configuration 类会继续解析
// 4. 处理类上的 @Import 注解,用 @Import 可以引入其他的 @Configuration 类,如果引入的类型是 ImportSelector, 就会根据 selectImports 返回的类型做导入
// 5. 处理类上的 @ImportResource 注解,导入资源文件并解析
// 6. 最后迭代所有方法,找出有 @Bean 方法,解析出 BeanDefinitions
parser.parse(candidates);
parser.validate();

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

if (this.reader == null) {
this.reader = new ConfigurationClassBeanDefinitionReader(
registry, this.sourceExtractor, this.resourceLoader, this.environment,
this.importBeanNameGenerator, parser.getImportRegistry());
}

// 将 BeanDefinitions 注册到 beanFactory
this.reader.loadBeanDefinitions(configClasses);

// 记录已经解析的 @Configuration 类
alreadyParsed.addAll(configClasses);

candidates.clear();
if (registry.getBeanDefinitionCount() > candidateNames.length) {
String[] newCandidateNames = registry.getBeanDefinitionNames();
Set<String> oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames));

// alreadyParsedClasses 记录已经解析的 @Configuration 类,方便之后排除
Set<String> alreadyParsedClasses = new HashSet<>();
for (ConfigurationClass configurationClass : alreadyParsed) {
alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
}

// 在 registry 中找出新注册的 @Configuration 类
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()); // 循环处理候选类

if (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
}

if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {
((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache();
}
}