优化ClassPathBeanDefinitionScanner源码分析

This commit is contained in:
xuchengsheng 2023-11-08 18:07:00 +08:00
parent ccd76c5103
commit cb55dd7db0

View File

@ -15,16 +15,21 @@
### 一、知识储备
1. **Bean定义**
- 了解Bean的概念以及如何定义和配置Bean是非常重要的。这包括Bean的ID、类名、属性注入、依赖关系等。
2. **Spring注解**
+ 我们需要熟悉 Spring 的注解,如 `@Component``@Configuration``@ComponentScan` 等,因为 `ClassPathBeanDefinitionScanner` 类就是用来解析此类注解的。
3. **类路径和包结构**
+ 了解类路径是什么,如何设置类路径,以及包的结构和命名规范,因为 `ClassPathBeanDefinitionScanner` 会在类路径上扫描包和类。
4. **`ResourceLoader`**
- `ResourceLoader` 可以用于获取资源这些资源可以是文件、类路径上的资源、URL、甚至是远程资源。它提供了一种统一的方式来加载资源无论这些资源位于何处。[点击查看ResourceLoader接口](https://github.com/xuchengsheng/spring-reading/tree/master/spring-resources/spring-resource-resourceLoader)
5. **`Resource`**
- `Resource` 代表一个资源可以是文件、类路径上的文件、URL 等。它提供了对资源的抽象和访问方法。[点击查看Resource接口](https://github.com/xuchengsheng/spring-reading/tree/master/spring-resources/spring-resource)
- `Resource` 代表一个资源可以是文件、类路径上的文件、URL 等。它提供了对资源的抽象和访问方法。
- [点击查看Resource接口](https://github.com/xuchengsheng/spring-reading/tree/master/spring-resources/spring-resource)
2. **`ResourceLoader`**
- `ResourceLoader` 可以用于获取资源这些资源可以是文件、类路径上的资源、URL、甚至是远程资源。它提供了一种统一的方式来加载资源无论这些资源位于何处。
- [点击查看ResourceLoader接口](https://github.com/xuchengsheng/spring-reading/tree/master/spring-resources/spring-resource-resourceLoader)
3. **`MetadataReader`**
+ `MetadataReader` 是 Spring 框架中用于读取类文件和类元数据的接口,它提供了有关类的信息,包括类名、注解、父类信息等。在 `ClassPathBeanDefinitionScanner` 中,`MetadataReader` 被用于扫描类路径,识别候选的 Bean 类,并读取类的元数据以创建相应的 `BeanDefinition`
+ [点击查看MetadataReader接口](https://github.com/xuchengsheng/spring-reading/tree/master/spring-metadata/spring-metadata-metadataReader)
4. **`AnnotationMetadata`**
- `AnnotationMetadata` 是 Spring 框架中用于处理类上的注解信息的接口,它提供了对类上注解信息的访问和操作方法。 `AnnotatedBeanDefinitionReader` 利用 `AnnotationMetadata` 解析类上的注解信息,并将其转化为 Spring 的 BeanDefinition。
- [点击查看AnnotationMetadata接口](https://github.com/xuchengsheng/spring-reading/tree/master/spring-metadata/spring-metadata-annotationMetadata)
5. **`BeanDefinition`**
- `BeanDefinition` 是 Spring 中描述和管理 Bean 配置的核心概念,它包括了有关 Bean 的信息,如类名、作用域、依赖关系、初始化方法等,而 `AnnotatedBeanDefinitionReader` 的主要任务之一是将使用注解配置的类转化为 `BeanDefinition` 并注册到 Spring 容器中。
- [点击查看BeanDefinition接口](https://github.com/xuchengsheng/spring-reading/tree/master/spring-beans/spring-bean-beanDefinition)
### 二、基本描述
@ -100,6 +105,7 @@ MyRepository = com.xcs.spring.repository.MyRepository@778d1062
~~~mermaid
sequenceDiagram
Title: ClassPathBeanDefinitionScanner时序图
par 注册默认过滤器阶段
ClassPathBeanDefinitionScannerDemo->>ClassPathBeanDefinitionScanner:new ClassPathBeanDefinitionScanner(registry)
note right of ClassPathBeanDefinitionScannerDemo: 创建 ClassPathBeanDefinitionScanner 实例,并关联到注册表
@ -112,21 +118,22 @@ note over ClassPathBeanDefinitionScanner: 创建 ClassPathBeanDefinitionScanner
ClassPathBeanDefinitionScanner->>ClassPathBeanDefinitionScanner:registerDefaultFilters()
note over ClassPathBeanDefinitionScanner: 注册默认的组件过滤器
ClassPathBeanDefinitionScanner->>ClassPathBeanDefinitionScannerDemo:返回scanner
note over ClassPathBeanDefinitionScanner,ClassPathBeanDefinitionScannerDemo: 返回 ClassPathBeanDefinitionScanner 实例
end
par 扫描Bean定义阶段
note left of ClassPathBeanDefinitionScanner: 返回 ClassPathBeanDefinitionScanner 实例
ClassPathBeanDefinitionScannerDemo->>ClassPathBeanDefinitionScanner:scan(basePackages)
note right of ClassPathBeanDefinitionScannerDemo: 执行组件扫描操作
note over ClassPathBeanDefinitionScannerDemo,ClassPathBeanDefinitionScanner: 执行组件扫描操作
ClassPathBeanDefinitionScanner->>ClassPathBeanDefinitionScanner:doScan(basePackages)
note over ClassPathBeanDefinitionScanner: 执行组件扫描操作
ClassPathBeanDefinitionScanner->>ClassPathScanningCandidateComponentProvider:findCandidateComponents(basePackage)
note left of ClassPathScanningCandidateComponentProvider: 查找符合条件的候选组件
note over ClassPathScanningCandidateComponentProvider,ClassPathBeanDefinitionScanner: 查找符合条件的候选组件
ClassPathScanningCandidateComponentProvider->>ClassPathScanningCandidateComponentProvider:scanCandidateComponents(basePackage)
note over ClassPathScanningCandidateComponentProvider: 扫描候选组件
ClassPathScanningCandidateComponentProvider->>ClassPathScanningCandidateComponentProvider:isCandidateComponent(metadataReader)
note over ClassPathScanningCandidateComponentProvider: 判断是否是候选组件
ClassPathScanningCandidateComponentProvider->>AbstractTypeHierarchyTraversingFilter:match(metadataReader,metadataReaderFactory)
note left of AbstractTypeHierarchyTraversingFilter: 使用过滤器匹配
note over AbstractTypeHierarchyTraversingFilter,ClassPathScanningCandidateComponentProvider: 使用过滤器匹配
AbstractTypeHierarchyTraversingFilter->>AnnotationTypeFilter:matchSelf(metadataReader)
note left of AnnotationTypeFilter: 调用 matchSelf(metadataReader)
AnnotationTypeFilter->>AbstractTypeHierarchyTraversingFilter:返回是否匹配
@ -134,18 +141,22 @@ AbstractTypeHierarchyTraversingFilter->>ClassPathScanningCandidateComponentProvi
ClassPathScanningCandidateComponentProvider->>ClassPathScanningCandidateComponentProvider:candidates.add(sbd)
note over ClassPathScanningCandidateComponentProvider: 如果匹配,则将候选组件加入列表
ClassPathScanningCandidateComponentProvider->>ClassPathBeanDefinitionScanner:返回扫描到的Bean定义
ClassPathBeanDefinitionScanner->>AnnotationConfigUtils:processCommonDefinitionAnnotations(abd)
Note over ClassPathBeanDefinitionScanner, AnnotationConfigUtils: 处理常见的Bean定义注解
AnnotationConfigUtils->>AnnotationConfigUtils:processCommonDefinitionAnnotations(abd,metadata)
Note over AnnotationConfigUtils: 处理 Bean 的元数据信息
ClassPathBeanDefinitionScanner->>ClassPathBeanDefinitionScanner:checkCandidate(beanName, candidate)
note over ClassPathBeanDefinitionScanner: 检查候选组件
ClassPathBeanDefinitionScanner->>ClassPathBeanDefinitionScanner:registerBeanDefinition(definitionHolder,registry)
note over ClassPathBeanDefinitionScanner: 注册 Bean 定义
ClassPathBeanDefinitionScanner->>AnnotationConfigUtils:registerBeanDefinition(definitionHolder,registry)
note over ClassPathBeanDefinitionScanner: 注册 Bean 定义
note over ClassPathBeanDefinitionScanner,AnnotationConfigUtils: 注册 Bean 定义
ClassPathBeanDefinitionScanner->>AnnotationConfigUtils:registerAnnotationConfigProcessors(registry)
note right of ClassPathBeanDefinitionScanner: 启用注解驱动的配置
note over ClassPathBeanDefinitionScanner,AnnotationConfigUtils: 启用注解驱动的配置
AnnotationConfigUtils->>AnnotationConfigUtils:registerAnnotationConfigProcessors(registry,source)
note over AnnotationConfigUtils: 启用注解驱动的配置
end
~~~
@ -254,7 +265,7 @@ public int scan(String... basePackages) {
}
```
> `org.springframework.context.annotation.ClassPathBeanDefinitionScanner#scan`步骤1
> [`org.springframework.context.annotation.ClassPathBeanDefinitionScanner#scan`步骤1]
`org.springframework.context.annotation.ClassPathBeanDefinitionScanner#doScan`方法中,主要负责找到符合条件的类,处理它们,并注册为 Spring Bean。
@ -263,29 +274,35 @@ protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
Assert.notEmpty(basePackages, "At least one base package must be specified");
Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
for (String basePackage : basePackages) {
// 查找符合条件的 BeanDefinition 候选类
// 步骤1: 查找符合条件的 BeanDefinition 候选类
Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
for (BeanDefinition candidate : candidates) {
// 解析 Bean 的作用域信息
// 步骤2: 解析 Bean 的作用域信息
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
candidate.setScope(scopeMetadata.getScopeName());
// 生成 Bean 的名称
// 步骤3: 生成 Bean 的名称
String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
// 步骤4: 对 BeanDefinition 进行进一步处理
if (candidate instanceof AbstractBeanDefinition) {
// 对 BeanDefinition 进行进一步处理
postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
}
// 步骤5: 处理通用的注解
if (candidate instanceof AnnotatedBeanDefinition) {
// 处理通用的注解
AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
}
// 步骤6: 注册BeanDefinition
if (checkCandidate(beanName, candidate)) {
// 创建 BeanDefinitionHolder 并注册为 BeanDefinition
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
// 处理 Bean 的作用域代理模式
definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
beanDefinitions.add(definitionHolder);
// 将 BeanDefinition 注册到 BeanDefinitionRegistry 中
// 步骤6.1 将 BeanDefinition 注册到 BeanDefinitionRegistry 中
registerBeanDefinition(definitionHolder, this.registry);
}
}
@ -294,6 +311,8 @@ protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
}
```
> [`org.springframework.context.annotation.ClassPathBeanDefinitionScanner#doScan`步骤1]
`org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider#findCandidateComponents`方法中,先是走组件索引中获取候选 `BeanDefinition` ,还是执行标准的包扫描操作。
```java
@ -431,7 +450,114 @@ protected boolean matchSelf(MetadataReader metadataReader) {
}
```
> `org.springframework.context.annotation.ClassPathBeanDefinitionScanner#scan`步骤2
> [`org.springframework.context.annotation.ClassPathBeanDefinitionScanner#doScan`步骤2]
`org.springframework.context.annotation.AnnotationConfigUtils#processCommonDefinitionAnnotations(abd)`方法中,处理 Bean 定义上的常见注解,以确保 Bean 在容器中的行为和属性符合这些注解的规定。
```java
public static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd) {
processCommonDefinitionAnnotations(abd, abd.getMetadata());
}
```
`org.springframework.context.annotation.AnnotationConfigUtils#processCommonDefinitionAnnotations(abd,metadata)`方法中,处理常见的 Bean 定义注解,如 `@Lazy``@Primary``@DependsOn``@Role``@Description`
```java
static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd, AnnotatedTypeMetadata metadata) {
// 处理 @Lazy 注解
AnnotationAttributes lazy = attributesFor(metadata, Lazy.class);
if (lazy != null) {
abd.setLazyInit(lazy.getBoolean("value"));
} else if (abd.getMetadata() != metadata) {
lazy = attributesFor(abd.getMetadata(), Lazy.class);
if (lazy != null) {
abd.setLazyInit(lazy.getBoolean("value"));
}
}
// 处理 @Primary 注解
if (metadata.isAnnotated(Primary.class.getName())) {
abd.setPrimary(true);
}
// 处理 @DependsOn 注解
AnnotationAttributes dependsOn = attributesFor(metadata, DependsOn.class);
if (dependsOn != null) {
abd.setDependsOn(dependsOn.getStringArray("value"));
}
// 处理 @Role 注解
AnnotationAttributes role = attributesFor(metadata, Role.class);
if (role != null) {
abd.setRole(role.getNumber("value").intValue());
}
// 处理 @Description 注解
AnnotationAttributes description = attributesFor(metadata, Description.class);
if (description != null) {
abd.setDescription(description.getString("value"));
}
}
```
> [`org.springframework.context.annotation.ClassPathBeanDefinitionScanner#doScan`步骤6]
`org.springframework.context.annotation.ClassPathBeanDefinitionScanner#checkCandidate`方法中,确保在注册 Bean 定义时,不会出现相同名称的 Bean 定义,或者如果名称相同,那么它们必须是兼容的。如果出现不兼容的情况,将抛出异常以防止冲突的 Bean 定义被注册。
```java
protected boolean checkCandidate(String beanName, BeanDefinition beanDefinition) throws IllegalStateException {
if (!this.registry.containsBeanDefinition(beanName)) {
// 如果注册表中不包含具有相同名称的Bean定义返回true表示候选的Bean可以被注册。
return true;
}
BeanDefinition existingDef = this.registry.getBeanDefinition(beanName);
BeanDefinition originatingDef = existingDef.getOriginatingBeanDefinition();
if (originatingDef != null) {
existingDef = originatingDef;
}
if (isCompatible(beanDefinition, existingDef)) {
// 如果候选的Bean定义与已存在的Bean定义兼容返回false表示不需要覆盖已存在的Bean定义。
return false;
}
throw new ConflictingBeanDefinitionException("Annotation-specified bean name '" + beanName +
"' for bean class [" + beanDefinition.getBeanClassName() + "] conflicts with existing, " +
"non-compatible bean definition of same name and class [" + existingDef.getBeanClassName() + "]");
// 如果候选的Bean定义与已存在的Bean定义不兼容抛出异常以防止冲突的Bean定义被注册。
}
```
> [`org.springframework.context.annotation.ClassPathBeanDefinitionScanner#doScan`步骤6.1]
`org.springframework.context.annotation.ClassPathBeanDefinitionScanner#registerBeanDefinition`方法中,又调用了另外一个方法。
```java
protected void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) {
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, registry);
}
```
`org.springframework.beans.factory.support.BeanDefinitionReaderUtils#registerBeanDefinition`方法中将Bean定义注册到Spring容器的Bean定义注册表中并处理别名的注册。
```java
public static void registerBeanDefinition(
BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
throws BeanDefinitionStoreException {
// Register bean definition under primary name.
String beanName = definitionHolder.getBeanName();
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
// Register aliases for bean name, if any.
String[] aliases = definitionHolder.getAliases();
if (aliases != null) {
for (String alias : aliases) {
registry.registerAlias(beanName, alias);
}
}
}
```
> [`org.springframework.context.annotation.ClassPathBeanDefinitionScanner#scan`步骤2]
`org.springframework.context.annotation.AnnotationConfigUtils#registerAnnotationConfigProcessors(registry)`方法中,注解配置处理器注册到 Spring 容器中,从而启用注解驱动的配置。