Skip to content

Latest commit

 

History

History
677 lines (563 loc) · 38.2 KB

File metadata and controls

677 lines (563 loc) · 38.2 KB

ClassPathBeanDefinitionScanner

一、知识储备

  1. Resource
    • Resource 代表一个资源,可以是文件、类路径上的文件、URL 等。它提供了对资源的抽象和访问方法。
    • 点击查看Resource接口
  2. ResourceLoader
    • ResourceLoader 可以用于获取资源,这些资源可以是文件、类路径上的资源、URL、甚至是远程资源。它提供了一种统一的方式来加载资源,无论这些资源位于何处。
    • 点击查看ResourceLoader接口
  3. MetadataReader
    • MetadataReader 是 Spring 框架中用于读取类文件和类元数据的接口,它提供了有关类的信息,包括类名、注解、父类信息等。在 ClassPathBeanDefinitionScanner 中,MetadataReader 被用于扫描类路径,识别候选的 Bean 类,并读取类的元数据以创建相应的 BeanDefinition
    • 点击查看MetadataReader接口
  4. AnnotationMetadata
    • AnnotationMetadata 是 Spring 框架中用于处理类上的注解信息的接口,它提供了对类上注解信息的访问和操作方法。 AnnotatedBeanDefinitionReader 利用 AnnotationMetadata 解析类上的注解信息,并将其转化为 Spring 的 BeanDefinition。
    • 点击查看AnnotationMetadata接口
  5. BeanDefinition
    • BeanDefinition 是 Spring 中描述和管理 Bean 配置的核心概念,它包括了有关 Bean 的信息,如类名、作用域、依赖关系、初始化方法等,而 AnnotatedBeanDefinitionReader 的主要任务之一是将使用注解配置的类转化为 BeanDefinition 并注册到 Spring 容器中。
    • 点击查看BeanDefinition接口

二、基本描述

ClassPathBeanDefinitionScanner 类,用于在类路径上扫描指定包及其子包中的类,识别符合条件的类,并将其注册为 Spring Bean 的定义,从而实现组件扫描和自动装配,使我们能够方便地管理和配置应用程序中的 Bean。它允许我们定义过滤条件,以确定哪些类应被注册为 Bean,以及配合自动装配实现依赖注入,提高了应用程序的可维护性和扩展性。

三、主要功能

  1. 包扫描
    • 扫描类路径上的指定包及其子包中的类文件,用于寻找潜在的 Spring Bean 候选类。
  2. BeanDefinition注册
    • 将找到的符合条件的类注册为 Spring Bean 的定义(BeanDefinition)。这使得这些类的实例可以由 Spring 容器进行管理。
  3. 自动装配
    • 自动装配机制结合使用,以自动识别并注入依赖的 Bean。这降低了手动配置 Bean 依赖的需求,提高了应用程序的可维护性。
  4. 注解识别
    • 扫描器能够识别带有特定注解的类,例如 @Component@Service@Repository 等,然后将这些类注册为 Spring Bean。
  5. 过滤条件
    • 配置过滤条件,以决定哪些类应该被注册为 Bean。过滤条件可以是注解类型、类名规则、类实现的接口等,从而筛选出符合条件的类。
  6. Bean 名称生成
    • 自动生成 Bean 的名称,通常是类名的首字母小写形式,但也可以通过配置进行自定义。
  7. 自定义配置
    • 通过配置 ClassPathBeanDefinitionScanner 的属性来自定义其行为,例如指定要扫描的包、设置过滤条件、配置 Bean 名称生成规则等。

四、最佳实践

创建 DefaultListableBeanFactory 和关联的 ClassPathBeanDefinitionScanner 对象,然后使用扫描器的 scan 方法扫描指定包中的类,将这些类注册为 Spring Bean,最终能够通过工厂获取并使用这些 Bean。

public class ClassPathBeanDefinitionScannerDemo {

    public static void main(String[] args) {
        // 创建一个 AnnotationConfigApplicationContext
        DefaultListableBeanFactory factory = new DefaultListableBeanFactory();

        // 创建 ClassPathBeanDefinitionScanner 并将其关联到容器
        ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(factory);

        // 使用 ClassPathBeanDefinitionScanner的scan方法扫描Bean对象
        scanner.scan("com.xcs.spring");

        System.out.println("MyController = " + factory.getBean(MyController.class));
        System.out.println("MyService = " + factory.getBean(MyService.class));
        System.out.println("MyRepository = " + factory.getBean(MyRepository.class));
    }
}

@Controller@Service@Repository。这些注解通常用于标记不同层次的组件,以便 Spring 容器可以自动识别和注册它们为 Spring Bean。

@Controller
public class MyController {
}

@Service
public class MyService {
}

@Repository
public class MyRepository {
}

运行结果发现, ClassPathBeanDefinitionScanner 成功扫描了指定包中的类,并将这些类注册为 Spring Bean。

MyController = com.xcs.spring.controller.MyController@1e802ef9
MyService = com.xcs.spring.service.MyService@2b6faea6
MyRepository = com.xcs.spring.repository.MyRepository@778d1062

五、时序图

sequenceDiagram
Title: ClassPathBeanDefinitionScanner时序图

par 注册默认过滤器阶段
ClassPathBeanDefinitionScannerDemo->>ClassPathBeanDefinitionScanner:new ClassPathBeanDefinitionScanner(registry)
note right of ClassPathBeanDefinitionScannerDemo: 创建 ClassPathBeanDefinitionScanner 实例,并关联到注册表
ClassPathBeanDefinitionScanner->>ClassPathBeanDefinitionScanner:ClassPathBeanDefinitionScanner(registry,useDefaultFilters)
note over ClassPathBeanDefinitionScanner: 创建 ClassPathBeanDefinitionScanner 实例,启用默认过滤器
ClassPathBeanDefinitionScanner->>ClassPathBeanDefinitionScanner:ClassPathBeanDefinitionScanner(registry,useDefaultFilters,environment)
note over ClassPathBeanDefinitionScanner: 创建 ClassPathBeanDefinitionScanner 实例,设置环境信息
ClassPathBeanDefinitionScanner->>ClassPathBeanDefinitionScanner:ClassPathBeanDefinitionScanner(registry,useDefaultFilters,environment,resourceLoader)
note over ClassPathBeanDefinitionScanner: 创建 ClassPathBeanDefinitionScanner 实例,设置资源加载器
ClassPathBeanDefinitionScanner->>ClassPathBeanDefinitionScanner:registerDefaultFilters()
note over ClassPathBeanDefinitionScanner: 注册默认的组件过滤器
ClassPathBeanDefinitionScanner->>ClassPathBeanDefinitionScannerDemo:返回scanner
note over ClassPathBeanDefinitionScanner,ClassPathBeanDefinitionScannerDemo: 返回 ClassPathBeanDefinitionScanner 实例
end

par 扫描Bean定义阶段
ClassPathBeanDefinitionScannerDemo->>ClassPathBeanDefinitionScanner:scan(basePackages)
note over ClassPathBeanDefinitionScannerDemo,ClassPathBeanDefinitionScanner: 执行组件扫描操作
ClassPathBeanDefinitionScanner->>ClassPathBeanDefinitionScanner:doScan(basePackages)
note over ClassPathBeanDefinitionScanner: 执行组件扫描操作
ClassPathBeanDefinitionScanner->>ClassPathScanningCandidateComponentProvider:findCandidateComponents(basePackage)
note over ClassPathScanningCandidateComponentProvider,ClassPathBeanDefinitionScanner: 查找符合条件的候选组件
ClassPathScanningCandidateComponentProvider->>ClassPathScanningCandidateComponentProvider:scanCandidateComponents(basePackage)
note over ClassPathScanningCandidateComponentProvider: 扫描候选组件
ClassPathScanningCandidateComponentProvider->>ClassPathScanningCandidateComponentProvider:isCandidateComponent(metadataReader)
note over ClassPathScanningCandidateComponentProvider: 判断是否是候选组件
ClassPathScanningCandidateComponentProvider->>AbstractTypeHierarchyTraversingFilter:match(metadataReader,metadataReaderFactory)
note over AbstractTypeHierarchyTraversingFilter,ClassPathScanningCandidateComponentProvider: 使用过滤器匹配
AbstractTypeHierarchyTraversingFilter->>AnnotationTypeFilter:matchSelf(metadataReader)
note left of AnnotationTypeFilter: 调用 matchSelf(metadataReader)
AnnotationTypeFilter->>AbstractTypeHierarchyTraversingFilter:返回是否匹配
AbstractTypeHierarchyTraversingFilter->>ClassPathScanningCandidateComponentProvider:返回是否匹配
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,AnnotationConfigUtils: 注册 Bean 定义
ClassPathBeanDefinitionScanner->>AnnotationConfigUtils:registerAnnotationConfigProcessors(registry)
note over ClassPathBeanDefinitionScanner,AnnotationConfigUtils: 启用注解驱动的配置
AnnotationConfigUtils->>AnnotationConfigUtils:registerAnnotationConfigProcessors(registry,source)
note over AnnotationConfigUtils: 启用注解驱动的配置
end

六、源码分析

注册默认过滤器阶段

org.springframework.context.annotation.ClassPathBeanDefinitionScanner#ClassPathBeanDefinitionScanner(registry)方法中,实际上是通过委派给另一个构造函数来创建,并且在第二个参数设置为 true ,表示会包括注册注解配置处理器(Annotation Config Processors),这通常用于支持注解配置,包括 @Component@Service@Repository 等注解。

public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry) {
    this(registry, true);
}

org.springframework.context.annotation.ClassPathBeanDefinitionScanner#ClassPathBeanDefinitionScanner(registry,useDefaultFilters)方法中,实际上是通过委派给另一个构造函数来创建,并且获取了上下文的环境变量进行传递。

public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters) {
	this(registry, useDefaultFilters, getOrCreateEnvironment(registry));
}

org.springframework.context.annotation.ClassPathBeanDefinitionScanner#ClassPathBeanDefinitionScanner(registry,useDefaultFilters,environment)方法中,实际上是通过委派给另一个构造函数来创建,最后一个参数是 ResourceLoader,如果 BeanDefinitionRegistry 也是 ResourceLoader 的实例,那么它会将 ResourceLoader 传递给后面的构造函数。

public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters,
			Environment environment) {
    this(registry, useDefaultFilters, environment,
         (registry instanceof ResourceLoader ? (ResourceLoader) registry : null));
}

org.springframework.context.annotation.ClassPathBeanDefinitionScanner#ClassPathBeanDefinitionScanner(registry,useDefaultFilters,environment,resourceLoader)方法中,我们重点关注registerDefaultFilters()方法,此方法主要是注册默认的过滤器,这些过滤器用于扫描默认的注解类,如 @Component@Service@Repository 等。

public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters,
			Environment environment, @Nullable ResourceLoader resourceLoader) {
    // 确保 BeanDefinitionRegistry 不为空
    Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
    this.registry = registry;

    // 如果需要使用默认过滤器,注册默认过滤器
    if (useDefaultFilters) {
        registerDefaultFilters();
    }

    // 设置环境信息
    setEnvironment(environment);
    
    // 设置资源加载器(ResourceLoader)
    setResourceLoader(resourceLoader);
}

org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider#registerDefaultFilters方法中, 主要目的就是注册@Component 注解,用于扫描和识别标记为组件的类,同时还提供了对一些 Java EE 规范中的注解的支持。

protected void registerDefaultFilters() {
    // 向 includeFilters 集合中添加默认的过滤器
    this.includeFilters.add(new AnnotationTypeFilter(Component.class));
    ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader();

    // 尝试注册 JSR-250 'javax.annotation.ManagedBean' 过滤器(如果可用)
    try {
        this.includeFilters.add(new AnnotationTypeFilter(
            ((Class<? extends Annotation>) ClassUtils.forName("javax.annotation.ManagedBean", cl)), false));
        logger.trace("JSR-250 'javax.annotation.ManagedBean' found and supported for component scanning");
    }
    catch (ClassNotFoundException ex) {
        // 如果 JSR-250 1.1 API(包括在 Java EE 6 中)不可用,简单地跳过。
    }

    // 尝试注册 JSR-330 'javax.inject.Named' 过滤器(如果可用)
    try {
        this.includeFilters.add(new AnnotationTypeFilter(
            ((Class<? extends Annotation>) ClassUtils.forName("javax.inject.Named", cl)), false));
        logger.trace("JSR-330 'javax.inject.Named' annotation found and supported for component scanning");
    }
    catch (ClassNotFoundException ex) {
        // 如果 JSR-330 API 不可用,简单地跳过。
    }
}

扫描Bean定义阶段

org.springframework.context.annotation.ClassPathBeanDefinitionScanner#scan方法中,实际是调用 doScan 方法来扫描指定的包,查找符合条件的类,并将它们注册为 BeanDefinition,另外还计算新的 BeanDefinition 计数与扫描前的计数之差。

public int scan(String... basePackages) {
    // 记录扫描开始时的 BeanDefinition 数量
    int beanCountAtScanStart = this.registry.getBeanDefinitionCount();

    // 步骤1: 执行扫描操作
    doScan(basePackages);

    // 步骤2: 注册注解配置处理器(如果需要的话)
    if (this.includeAnnotationConfig) {
        AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
    }

    // 返回扫描后的 BeanDefinition 数量与扫描开始前的数量的差,表示扫描期间注册的新 BeanDefinition 数量
    return (this.registry.getBeanDefinitionCount() - beanCountAtScanStart);
}

[org.springframework.context.annotation.ClassPathBeanDefinitionScanner#scan步骤1]

org.springframework.context.annotation.ClassPathBeanDefinitionScanner#doScan方法中,主要负责找到符合条件的类,处理它们,并注册为 Spring Bean。

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) {
        // 步骤1: 查找符合条件的 BeanDefinition 候选类
        Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
        for (BeanDefinition candidate : candidates) {
            
            // 步骤2: 解析 Bean 的作用域信息
            ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
            candidate.setScope(scopeMetadata.getScopeName());
            
            // 步骤3: 生成 Bean 的名称
            String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
            
            // 步骤4: 对 BeanDefinition 进行进一步处理
            if (candidate instanceof AbstractBeanDefinition) {
                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);
                // 步骤6.1 将 BeanDefinition 注册到 BeanDefinitionRegistry 中
                registerBeanDefinition(definitionHolder, this.registry);
            }
        }
    }
    return beanDefinitions;
}

[org.springframework.context.annotation.ClassPathBeanDefinitionScanner#doScan步骤1]

org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider#findCandidateComponents方法中,先是走组件索引中获取候选 BeanDefinition ,还是执行标准的包扫描操作。

public Set<BeanDefinition> findCandidateComponents(String basePackage) {
    if (this.componentsIndex != null && indexSupportsIncludeFilters()) {
        // 如果存在组件索引并且索引支持包含过滤器
        return addCandidateComponentsFromIndex(this.componentsIndex, basePackage);
    }
    else {
        // 否则,执行标准的扫描操作
        return scanCandidateComponents(basePackage);
    }
}

org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider#scanCandidateComponents方法中,扫描指定包路径下的类,并找到候选的 BeanDefinition。它包含了文件扫描、元数据读取和过滤候选类的逻辑。

private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
    // 创建一个用于存储候选 BeanDefinition 的集合
    Set<BeanDefinition> candidates = new LinkedHashSet<>();
    try {
        // 构建包搜索路径,使用类路径前缀和解析的基本包路径
        String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
            resolveBasePackage(basePackage) + '/' + this.resourcePattern;
        // 获取资源模式解析器的资源数组
        Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);
        // 检查日志级别是否开启跟踪和调试
        boolean traceEnabled = logger.isTraceEnabled();
        boolean debugEnabled = logger.isDebugEnabled();
        // 遍历资源数组,查找候选 BeanDefinition
        for (Resource resource : resources) {
            // ... [代码部分省略以简化]
            if (resource.isReadable()) {
                try {
                    // 获取资源的元数据读取器
                    MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
                    if (isCandidateComponent(metadataReader)) {
                        // 如果是候选的组件类
                        ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
                        sbd.setSource(resource);
                        // 如果是候选的组件类,添加到候选 BeanDefinition 集合
                        if (isCandidateComponent(sbd)) {
                            // ... [代码部分省略以简化]
                            candidates.add(sbd);
                        }
                        else {
                            // ... [代码部分省略以简化]
                        }
                    }
                    else {
                        // ... [代码部分省略以简化]
                    }
                }
                catch (Throwable ex) {
                    // ... [代码部分省略以简化]
                }
            }
            else {
                // ... [代码部分省略以简化]
            }
        }
    }
    catch (IOException ex) {
        // ... [代码部分省略以简化]
    }
    // 返回找到的候选 BeanDefinition 集合
    return candidates;
}

org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider#isCandidateComponent(metadataReader)方法中,主要用于在组件扫描过程中,根据过滤器的规则和条件检查,判断是否给定的类是一个候选的组件类,用于决定是否将其注册为 Spring BeanDefinition

protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
    // 遍历排除过滤器列表
    for (TypeFilter tf : this.excludeFilters) {
        // 如果匹配了任何一个排除过滤器,将其标记为不是候选组件
        if (tf.match(metadataReader, getMetadataReaderFactory())) {
            return false;
        }
    }
    
    // 遍历包含过滤器列表
    for (TypeFilter tf : this.includeFilters) {
        // 如果匹配了任何一个包含过滤器
        if (tf.match(metadataReader, getMetadataReaderFactory())) {
            // 检查是否符合条件(通常用于进一步条件检查)
            return isConditionMatch(metadataReader);
        }
    }
    
    // 默认情况下,不是候选组件
    return false;
}

org.springframework.core.type.filter.AbstractTypeHierarchyTraversingFilter#match(metadataReader, metadataReaderFactory)方法中, 主要用于在过滤过程中检查是否应该匹配给定的 MetadataReader

@Override
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
    throws IOException {

    // 优化:首先检查是否可以直接匹配当前的 metadataReader
    if (matchSelf(metadataReader)) {
        return true;
    }
    // 获取类元数据信息
    ClassMetadata metadata = metadataReader.getClassMetadata();
    
    // 检查是否匹配类的名称
    if (matchClassName(metadata.getClassName())) {
        return true;
    }

    // ... [代码部分省略以简化]

    // 如果没有任何条件匹配成功,返回 false 表示不匹配
    return false;
}

org.springframework.core.type.filter.AnnotationTypeFilter#matchSelf方法中,主要用于检查给定的 metadataReader 是否满足特定的匹配条件。如果 metadataReader 是一个类,该类被 @Component 注解修饰,那么 matchSelf 方法将被用于检查是否匹配 @Component 注解或其元注解。

@Override
protected boolean matchSelf(MetadataReader metadataReader) {
    // 获取注解元数据信息
    AnnotationMetadata metadata = metadataReader.getAnnotationMetadata();
    
    // 检查是否包含指定的注解或其元注解
    return metadata.hasAnnotation(this.annotationType.getName()) ||
        (this.considerMetaAnnotations && metadata.hasMetaAnnotation(this.annotationType.getName()));
}

[org.springframework.context.annotation.ClassPathBeanDefinitionScanner#doScan步骤2]

org.springframework.context.annotation.AnnotationConfigUtils#processCommonDefinitionAnnotations(abd)方法中,处理 Bean 定义上的常见注解,以确保 Bean 在容器中的行为和属性符合这些注解的规定。

public static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd) {
    processCommonDefinitionAnnotations(abd, abd.getMetadata());
}

org.springframework.context.annotation.AnnotationConfigUtils#processCommonDefinitionAnnotations(abd,metadata)方法中,处理常见的 Bean 定义注解,如 @Lazy@Primary@DependsOn@Role@Description

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 定义被注册。

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方法中,又调用了另外一个方法。

protected void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) {
    BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, registry);
}

org.springframework.beans.factory.support.BeanDefinitionReaderUtils#registerBeanDefinition方法中,将Bean定义注册到Spring容器的Bean定义注册表中,并处理别名的注册。

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 容器中,从而启用注解驱动的配置。

public static void registerAnnotationConfigProcessors(BeanDefinitionRegistry registry) {
    registerAnnotationConfigProcessors(registry, null);
}

org.springframework.context.annotation.AnnotationConfigUtils#registerAnnotationConfigProcessors(registry, source)方法中,主要目的是注册一些关键的注解配置处理器,以便支持注解驱动的配置和处理不同类型的注解。

public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
        BeanDefinitionRegistry registry, @Nullable Object source) {

    // 1. 如果 BeanDefinitionRegistry 是 DefaultListableBeanFactory 的实例,执行以下操作
    DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
    if (beanFactory != null) {
        // 1.1 检查当前的依赖比较器是否是 AnnotationAwareOrderComparator 的实例,如果不是,设置依赖比较器为 AnnotationAwareOrderComparator.INSTANCE,用于处理注解驱动排序。
        if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
            beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
        }
        // 1.2 检查当前的自动装配候选解析器是否是 ContextAnnotationAutowireCandidateResolver 的实例,如果不是,设置自动装配候选解析器为 ContextAnnotationAutowireCandidateResolver,用于处理注解驱动的自动装配。
        if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {
            beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
        }
    }

    // 2. 创建一个空的 LinkedHashSet 用于存储将要注册的 Bean 定义。
    Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);

    // 3. 检查是否已经注册了名为 CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME 的 Bean 定义。如果没有,创建一个 ConfigurationClassPostProcessor 类型的 Bean 定义,并将其添加到 BeanDefinitionRegistry 中。
    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));
    }

    // 4. 检查是否已经注册了名为 AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME 的 Bean 定义。如果没有,创建一个 AutowiredAnnotationBeanPostProcessor 类型的 Bean 定义,并将其添加到 BeanDefinitionRegistry 中。
    if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
        RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
        def.setSource(source);
        beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
    }

    // 5. 检查是否已经注册了名为 COMMON_ANNOTATION_PROCESSOR_BEAN_NAME 的 Bean 定义,这是用于支持 JSR-250 注解的处理器。如果没有,并且检测到 JSR-250 的支持,创建一个 CommonAnnotationBeanPostProcessor 类型的 Bean 定义,并将其添加到 BeanDefinitionRegistry 中。
    if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {
        RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
        def.setSource(source);
        beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
    }

    // 6. 检查是否已经注册了名为 PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME 的 Bean 定义,这是用于支持 JPA 注解的处理器。如果没有,并且检测到 JPA 的支持,创建一个 PersistenceAnnotationBeanPostProcessor 类型的 Bean 定义,并将其添加到 BeanDefinitionRegistry 中。
    if (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) {
        RootBeanDefinition def = new RootBeanDefinition();
        try {
            def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME,
                                                AnnotationConfigUtils.class.getClassLoader()));
        }
        catch (ClassNotFoundException ex) {
            throw new IllegalStateException(
						"Cannot load optional framework class: " + PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, ex);
        }
        def.setSource(source);
        beanDefs.add(registerPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME));
    }

    // 7. 检查是否已经注册了名为 EVENT_LISTENER_PROCESSOR_BEAN_NAME 的 Bean 定义。如果没有,创建一个 EventListenerMethodProcessor 类型的 Bean 定义,并将其添加到 BeanDefinitionRegistry 中。
    if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {
        RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);
        def.setSource(source);
        beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));
    }

    // 8. 检查是否已经注册了名为 EVENT_LISTENER_FACTORY_BEAN_NAME 的 Bean 定义。如果没有,创建一个 DefaultEventListenerFactory 类型的 Bean 定义,并将其添加到 BeanDefinitionRegistry 中。
    if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) {
        RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class);
        def.setSource(source);
        beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME));
    }

    // 9. 返回包含注册的 Bean 定义的 LinkedHashSet。
    return beanDefs;
}

七、与其他组件的关系

  1. BeanDefinitionLoader
    • Spring Boot 中的 BeanDefinitionLoader 负责加载 Bean 定义,通常与 ClassPathBeanDefinitionScanner 一起使用,以支持自动配置。
  2. AnnotationConfigApplicationContext
    • 这是 Spring Framework 中的 AnnotationConfigApplicationContext,它用于配置 Spring 应用程序上下文并支持注解驱动的配置。在内部,它可能使用 ClassPathBeanDefinitionScanner 来扫描和注册组件。
  3. ComponentScanAnnotationParser &ComponentScanBeanDefinitionParser
    • 这些类通常用于解析 @ComponentScan 注解,以指定需要扫描的包和组件。它们可能使用 ClassPathBeanDefinitionScanner 来执行扫描操作。
  4. AnnotationConfigWebApplicationContext
    • 这是 Spring Web 应用程序中的 AnnotationConfigWebApplicationContext,通常用于配置 Web 应用程序的 Spring 上下文。它可以使用 ClassPathBeanDefinitionScanner 来进行组件扫描。

八、常见问题

  1. ClassPathBeanDefinitionScanner 是什么?
    • 用于执行组件扫描和注册。它用于查找应用程序类路径上的标记为组件的类(如标有 @Component@Service@Repository 注解的类),并将它们注册为 Spring Bean。
  2. ClassPathBeanDefinitionScanner 的主要功能是什么?
    • 主要功能包括扫描指定包中的类,识别带有特定注解的类,将它们注册为 Spring Bean,并支持自动装配。它还支持自定义的过滤器,以便根据应用程序需求筛选要扫描和注册的类。
  3. 如何在 Spring 配置中使用 ClassPathBeanDefinitionScanner
    • 通常,ClassPathBeanDefinitionScanner 不会直接在配置文件中使用。它通常由 Spring 的注解驱动配置或 Spring Boot 的自动配置机制隐式使用。配置类中使用 @ComponentScan 注解来启用组件扫描,ClassPathBeanDefinitionScanner 将在内部使用。
  4. 如何自定义 ClassPathBeanDefinitionScanner 的行为?
    • 可以通过创建自定义组件扫描器并扩展 ClassPathBeanDefinitionScanner,然后使用自定义扫描器来覆盖默认的组件扫描行为。这允许我们自定义扫描过滤器、扫描路径等。
  5. ClassPathBeanDefinitionScanner 是否支持自定义注解?
    • 可以配置 ClassPathBeanDefinitionScanner 来扫描具有自定义注解的类。通过设置包含和排除过滤器,我们可以指定要扫描的自定义注解类型。
  6. ClassPathBeanDefinitionScanner 是否支持排除特定类?
    • 可以使用 ClassPathBeanDefinitionScanner 的过滤器来排除特定类,以防止它们被扫描和注册为 Spring Bean。
  7. ClassPathBeanDefinitionScanner 是否支持排除特定包?
    • 可以使用 ClassPathBeanDefinitionScanner 的过滤器来排除特定包中的类,以防止它们被扫描和注册为 Spring Bean。
  8. 如何在 Spring Boot 中使用 ClassPathBeanDefinitionScanner
    • 在 Spring Boot 应用程序中,通常不需要显式使用 ClassPathBeanDefinitionScanner。Spring Boot 使用自动配置机制来扫描和注册组件。如果需要自定义组件扫描,可以在配置类中使用 @ComponentScan 注解来指定要扫描的包。
  9. ClassPathBeanDefinitionScanner 是否支持排除特定注解?
    • 可以使用 ClassPathBeanDefinitionScanner 的过滤器来排除具有特定注解的类,以防止它们被扫描和注册为 Spring Bean。