Spring Framework之扫描注册机制(五)

一、前言

声明:Spring Framework将以本篇带来末结

通过前面五篇,我们对Bean加载、Bean依赖都有了深刻的认识,关于扫描Spring Framework是怎么做的了?通过下面2点我们将了解简单的Spring:
1.扫描注册机制的应用
2.游走ClassPathBeanDefinitionScanner扫描机制源码

二、扫描注册机制的应用

下面将会给未接触过的人也能一眼看懂,给接触过的人一个简短的温故

准备
类结构图
avatar
类结构

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
package mybean;

import org.springframework.stereotype.Component;

@Component
public class Bean1 {

}
-------------------------------------------------------------
package mybean;

import org.springframework.stereotype.Component;

@Component
public class Bean2 {

}
-------------------------------------------------------------
package mybean;

import org.springframework.context.annotation.ComponentScan;

@ComponentScan
public class ScanBean {

}

手动上下文扫描

  • junit代码块

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    @Test
    public void Test(){
    // 构建应用上下文
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
    context.scan("mybean");
    // 刷新应用上下文
    context.refresh();
    Arrays.asList(context.getBeanDefinitionNames())
    .forEach(System.out::println);
    }
  • 执行输出结果

    缺少scanBean原因:Spring Framework是过滤掉了一些Bean,原生的默认支持@Component扫描自动注册

    1
    2
    3
    4
    5
    6
    org.springframework.context.annotation.internalConfigurationAnnotationProcessor
    org.springframework.context.annotation.internalAutowiredAnnotationProcessor
    org.springframework.context.event.internalEventListenerProcessor
    org.springframework.context.event.internalEventListenerFactory
    bean1
    bean2

自动Bean配置扫描

  • junit代码块

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    @Test
    public void Test(){
    // 构建应用上下文
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
    context.register(ScanBean.class);
    // 刷新应用上下文
    context.refresh();
    Arrays.asList(context.getBeanDefinitionNames())
    .forEach(System.out::println);
    }
  • 执行输出结果

    1
    2
    3
    4
    5
    6
    7
    org.springframework.context.annotation.internalConfigurationAnnotationProcessor
    org.springframework.context.annotation.internalAutowiredAnnotationProcessor
    org.springframework.context.event.internalEventListenerProcessor
    org.springframework.context.event.internalEventListenerFactory
    scanBean
    bean1
    bean2

三、游走ClassPathBeanDefinitionScanner扫描机制源码

由于扫描注册有两套机制,下文呼应所有Spring Framework文章,全面对自动Bean配置扫描进行解析,其中手动上下文扫描也会走到其中,下面会重点说明;主要类为ConfigurationClassPostProcessor,执行时机为上下文刷新中invokeBeanFactoryPostProcessors(beanFactory);

ConfigurationClassPostProcessor结构图
avatar
ConfigurationClassPostProcessor

这是Spring的内置Bena配置对象,前文学了BeanDefinitionRegistryPostProcessor.postProcessBeanDefinitionRegistry();回调流程,这边直接跟进

avatar

由于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
//处理配置bean定义
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
String[] candidateNames = registry.getBeanDefinitionNames();

//筛选配置Bean
for (String beanName : candidateNames) {
BeanDefinition beanDef = registry.getBeanDefinition(beanName);
if (beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE) != null) {
//...
}
//检查配置bean
else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
//装载ScanBean
configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
}
}

//没有配置需要处理 -> 跳出
if (configCandidates.isEmpty()) {
return;
}

//优先级排序
configCandidates.sort((bd1, bd2) -> {
int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
return Integer.compare(i1, i2);
});

//为registry绑定BeanName生成器
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();
}

//配置类解析器 -> 解析配置
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 {
StartupStep processConfig = this.applicationStartup.start("spring.context.config-classes.parse");
parser.parse(candidates);//解析ScanBean⬅️
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());
}
//注册配置解析出来的Bean定义
this.reader.loadBeanDefinitions(configClasses);
//...
}
while (!candidates.isEmpty());

if (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
//注册导入单例
sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
}
//...
}

ConfigurationClassParser
avatar
avatar
avatar
avatar
ComponentScanAnnotationParser
avatar
ClassPathBeanDefinitionScanner

其中注册的逻辑就不进行说明了,可以看前面更系统的了解

avatar
ClassPathScanningCandidateComponentProvider

当前为单个包的扫描机制,与手动上下文扫描对应

avatar
avatar

  • Copyright: Copyright is owned by the author. For commercial reprints, please contact the author for authorization. For non-commercial reprints, please indicate the source.

请我喝杯咖啡吧~

支付宝
微信