Spring揭秘:ClassPathScanningProvider接口应用场景及实现原理!

news2024/9/27 9:23:19

Spring揭秘:ClassPathScanningCandidateComponentProvider接口应用场景及实现原理! - 程序员古德

技术应用场景

ClassPathScanningCandidateComponentProvider是Spring框架中一个非常核心的类,它主要用于在类路径下扫描并发现带有特定注解的组件,支持诸如@ComponentScan@Component@Service@Repository@Controller等注解的自动扫描和注册。

ClassPathScanningCandidateComponentProvider 解决了以下几个技术问题:

  1. 组件自动发现:在Spring应用程序中,会有大量的组件(如服务、控制器、存储库等),这些组件通常使用Spring的注解进行标记,手动配置这些组件可能会非常繁琐且容易出错,使用ClassPathScanningCandidateComponentProvider,Spring可以自动扫描类路径,发现并注册这些组件,从而大大简化了配置过程。
  2. 可扩展性:这个类提供了高度的可扩展性,可以通过覆盖其方法或提供自定义的过滤器来定制扫描过程,例如,可以指定只扫描特定包下的组件,或者只扫描带有特定注解的组件。
  3. 与Spring容器集成ClassPathScanningCandidateComponentProvider与Spring的ApplicationContext容器紧密集成,使用它发现的组件可以直接注册到容器中,使得这些组件能够在应用程序的其他部分中被自动装配和使用。
  4. 支持多种注解类型:这个类不仅支持Spring自带的注解(如@Component@Service等),还支持自定义注解,因此可以创建自己的注解,并使用ClassPathScanningCandidateComponentProvider在类路径中扫描带有这些注解的组件。

伪代码案例

下面是一个简单的示例,演示了如何使用 ClassPathScanningCandidateComponentProvider 类来扫描指定包路径下带有特定注解的类。

在这个例子中,使用带有 @Component 注解的类进行测试,如下代码。

首先,创建一些带有 @Component 注解的组件类作为扫描的目标。

// MyComponent1.java  
package com.example.components;  
  
import org.springframework.stereotype.Component;  
  
@Component  
public class MyComponent1 {  
    // ...  
}  
  
// MyComponent2.java  
package com.example.components;  
  
import org.springframework.stereotype.Component;  
  
@Component  
public class MyComponent2 {  
    // ...  
}

然后,编写一个客户端类,该类使用 ClassPathScanningCandidateComponentProvider 来扫描这些组件。

// ComponentScannerClient.java  
package com.example;  
  
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;  
import org.springframework.core.type.filter.AnnotationTypeFilter;  
import org.springframework.stereotype.Component;  
  
import java.io.IOException;  
import java.util.Set;  
  
public class ComponentScannerClient {  
  
    public static void main(String[] args) {  
        // 创建一个 ClassPathScanningCandidateComponentProvider 实例  
        ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(false);  
  
        // 添加一个过滤器,只包含带有 @Component 注解的类  
        scanner.addIncludeFilter(new AnnotationTypeFilter(Component.class));  
  
        // 指定要扫描的包路径  
        String basePackage = "com.example.components";  
  
        // 执行扫描并获取候选组件  
        Set<BeanDefinition> candidateComponents = scanner.findCandidateComponents(basePackage);  
  
        // 输出扫描结果  
        for (BeanDefinition beanDefinition : candidateComponents) {  
            System.out.println("Found component: " + beanDefinition.getBeanClassName());  
        }  
    }  
}

运行这个示例,控制台会输出类似下面的内容:

Found component: com.example.components.MyComponent1  
Found component: com.example.components.MyComponent2

核心API

ClassPathScanningCandidateComponentProvider 类提供了一系列的方法,用于配置扫描过程、执行扫描以及处理扫描结果。以下是该类中一些主要方法的含义:

  1. ClassPathScanningCandidateComponentProvider(boolean useDefaultFilters)
    • 构造函数,用于创建一个新的 ClassPathScanningCandidateComponentProvider 实例。
    • 参数 useDefaultFilters 指定是否应用默认的过滤器。如果为 true,则会自动包含对 @Component@Repository@Service@Controller 的支持。
  2. addIncludeFilter(TypeFilter includeFilter)
    • 添加一个包含过滤器,用于指定哪些类型的组件应该被包含在扫描结果中。
    • TypeFilter 是一个接口,可以通过实现该接口来定义自定义的过滤逻辑。
  3. addExcludeFilter(TypeFilter excludeFilter)
    • 添加一个排除过滤器,用于指定哪些类型的组件应该被排除在扫描结果之外。
    • 同样,TypeFilter 可以用于定义自定义的排除逻辑。
  4. findCandidateComponents(String basePackage)
    • 执行扫描操作,查找指定基础包及其子包下的候选组件。
    • 返回的是一个 Set<BeanDefinition>
  5. isCandidateComponent(MetadataReader metadataReader)
    • 判断给定的 MetadataReader 是否是一个候选组件。
    • 这个方法通常用于内部逻辑,但也可以被覆盖以实现自定义的候选组件判断逻辑。
  6. resetFilters(boolean includeDefaultFilters)
    • 重置之前添加的所有过滤器,并可以选择是否包含默认过滤器。
    • 这允许重用同一个 ClassPathScanningCandidateComponentProvider 实例进行多次不同的扫描操作。
  7. setEnvironment(Environment environment)
    • 设置用于解析属性占位符的 Environment 实例。
    • 这允许在扫描过程中使用 Spring 的环境抽象来解析例如占位符配置的值。
  8. setResourceLoader(ResourceLoader resourceLoader)
    • 设置用于加载资源的 ResourceLoader 实例。
    • 这允许在扫描过程中访问和加载类路径资源。
  9. setMetadataReaderFactory(MetadataReaderFactory metadataReaderFactory)
    • 设置用于创建 MetadataReader 实例的工厂。
    • 这允许自定义如何读取类的元数据。
  10. registerDefaultFilters()
    • 注册默认的过滤器。这个方法通常在构造函数中被调用,但也可以被覆盖以实现自定义的默认过滤器注册逻辑。

注意:这里列出的是一些核心方法,可能在不同的Spring版本中方法的数量会不一样,但是总体上差距不会非常大。

技术原理

ClassPathScanningCandidateComponentProvider类是Spring框架中用于扫描类路径以查找带特定注解的组件的关键类。它的实现原理基于Java的反射机制、类加载器以及Spring的内部元数据处理机制。

实现原理

1、类加载器和资源访问

  1. ClassPathScanningCandidateComponentProvider使用Java的类加载器(ClassLoader)来访问类路径上的资源,类加载器负责从文件系统、JAR文件或其他资源位置加载类。
  2. Spring利用类加载器的getResources方法来获取所有匹配给定包名的资源路径。

2、扫描和过滤

  1. 一旦获取了资源路径,ClassPathScanningCandidateComponentProvider就会扫描这些路径以查找候选组件。

  2. 扫描过程中,可以使用包含(include)和排除(exclude)过滤器来进一步细化扫描结果,这些过滤器基于注解、类名、包名或其他条件来过滤组件。

  3. 默认的过滤器通常会包含标注有@Component@Repository@Service@Controller注解的类。

3、元数据处理

  1. 对于扫描到的每个类,ClassPathScanningCandidateComponentProvider会使用MetadataReader来读取类的元数据,MetadataReader是Spring内部的一个接口,用于访问类的元数据而无需实际加载类。

  2. MetadataReaderFactory负责创建MetadataReader实例,默认情况下,它使用ASM库来读取类的字节码并提取元数据。

4、候选组件识别

  1. 通过分析元数据,ClassPathScanningCandidateComponentProvider能够确定一个类是否是一个候选组件,这是通过检查类上的注解来实现的。

  2. 如果一个类被识别为候选组件,它将被添加到扫描结果的集合中。

运行机制

底层算法大致如下:

  1. 初始化:配置 ClassPathScanningCandidateComponentProvider 实例,包括是否使用默认过滤器以及添加自定义的包含或排除过滤器。
  2. 扫描:调用 findCandidateComponents 方法并传入要扫描的基础包名,该方法内部会:1、使用类加载器的 getResources 方法获取所有匹配包名的资源路径。2、遍历这些资源路径,对每个路径执行扫描操作。
  3. 过滤和读取元数据:对于扫描到的每个资源(通常是 .class 文件),使用 MetadataReader 读取其元数据,并应用过滤器来确定是否应该将其包含为候选组件。
  4. 收集结果:将识别为候选组件的类信息收集起来并返回,这些信息通常用于后续的 Spring 容器初始化过程,如创建 Bean 定义等。

相关接口和类

  • TypeFilter:用于定义包含或排除过滤器的接口,实现该接口可以自定义过滤逻辑。
  • MetadataReaderMetadataReaderFactory:用于读取类的元数据而不实际加载类,这是通过直接访问类的字节码来实现的,通常使用 ASM 库来完成。
  • ResourceLoaderEnvironment:这些接口和类在扫描过程中不是必需的,但在某些情况下可以用于解析属性占位符或加载资源,它们提供了与 Spring 环境更紧密的集成。

关注我,每天学习互联网编程技术 - 程序员古德

END!
END!
END!

往期回顾

精品文章

Spring揭秘:Environment接口应用场景及实现原理!

Spring揭秘:AnnotationMetadata接口应用场景及实现原理!

Spring揭秘:BeanDefinitionBuilder接口应用场景及实现原理!

Spring揭秘:@import注解应用场景及实现原理!

Java并发基础:原子类之AtomicMarkableReference全面解析!

精彩视频

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1517256.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

关于MySQL数据库2

目录 前言: 1.mysql中常用的数据类型: 1.1数值类型: 1.1.1INT: 1.1.2FLOAT 和 DOUBLE: 1.1.3DECIMAL (或 NUMERIC): 1.2日期和时间类型: 1.2.1DATE: 1.2.2TIME: 1.2.3DATETIME: 1.2.4TIMESTAMP: 1.2.5YEAR: 1.3字符串类型: 1.3.1CHAR: 1.3.1VARCHAR: 1.3.1TEXT:…

java kafka客户端何时设置的kafka消费者默认值

kafka为什么有些属性没有配置却能正常工作&#xff0c;那是因为kafka-clients对有些消费者设置了默认值&#xff0c;具体看下ConsumerConfig类的静态模块&#xff0c;具体如下所示&#xff1a; kafka为什么有些属性没有配置却能正常工作&#xff0c;那是因为kafka-clients对有…

【软考】UML中的图之对象图

目录 1. 说明2. 图示3. 特性 1. 说明 1.对象图即object diagram2.展现了某一时刻一组对象以及它们之间的关系3.描述了在类图中所建立的事物的实例的静态快照4.对象图一般包括对象和链5.对象图展示的是对象之间关系&#xff0c;不存在交互&#xff0c;所以不是交互图 2. 图示 …

给电脑加硬件的办法 先找电脑支持的接口,再买相同接口的

需求&#xff1a;我硬盘太小&#xff0c;换或加一个大硬盘 结论&#xff1a;接口是NVMe PCIe 3.0 x4 1.找到硬盘型号 主硬盘 三星 MZALQ512HALU-000L2 (512 GB / 固态硬盘) 2.上官网查 或用bing查 非官方渠道信息&#xff0c;不确定。

智能物流新纪元:分布式I/O模块重塑仓储自动化

随着工业4.0概念的深入人心&#xff0c;物流行业正在经历前所未有的变革。在这个过程中&#xff0c;物流企业必须积极走向工业自动化、智能化&#xff0c;进而提高物流效率&#xff0c;降低物流成本&#xff0c;以便更好地满足客户和市场的需求。智能物流、仓库自动化已然是趋势…

云端巨擘:大数据与云计算的时代航向

文章目录 大数据时代大数据特点(4v1C大数据与云计算的关系 云计算云计算定义云计算特点云计算分类&#xff08;服务类型&#xff09;云计算实现机制云计算体系结构云计算的管理中间件层 大数据时代 大数据定义&#xff1a;海量数据或巨量数据&#xff0c;其规模巨大到无法通过…

经典排序算法之计数排序|c++代码实现

引言 排序算法c实现系列第8弹——计数排序。 计数排序是理解起来相对简单的一个排序算法&#xff0c; 计数排序 计数排序&#xff08;Counting Sort&#xff09;是一种非比较型的排序算法&#xff0c;它的基本思想是统计待排序数组中每个元素的出现次数&#xff0c;然后根据…

河南大学数据结构实验-顺序栈和链栈的实现

计算机与信息工程学院实验报告 姓名&#xff1a;杨馥瑞 学号&#xff1a;2212080042 专业&#xff1a;数据科学与大数据技术 年级&#xff1a;2022 课程&#xff1a;数据结构 主讲教师&#xff1a;袁彩虹老师 辅导教师&#xff1a;_______ 实验时间&…

【STL】set容器、pair队组与map容器

目录 1.修改set容器排序规则 2. set容器的各种函数 3.set构造函数multiset 4.创建pair队组 5.map容器 1.修改set容器排序规则 set容器会自动以升序的方式进行排序&#xff0c;想要改变可以制定排序规则&#xff0c;set<int,排序规则> s&#xff1b; 但需要注意&am…

Notepad++从文件夹查找文本内容

目录 一、背景二、Notepad搜索2.1 测试用例2.2 操作说明 一、背景 在日常的办公、学习或编程中&#xff0c;我们时长会遇到需要在大量文件中搜索特定文本内容的情况&#xff1a; 无论是快速定位某个项目中的代码片段&#xff1b;还是检索文档资料库中的相关信息等。 掌握如何…

【Python数据结构与判断5/7】列表的便捷操作

目录 目标 追加 列表的追加 列表的插入 生活场景应用 列表删除元素 变量作为列表元素 Debug 总结 目标 昨天&#xff0c;我们学习了列表&#xff0c;使用索引修改列表中的元素&#xff0c;以及通过切片获取指定元素。 今天我们会学习&#xff0c;如何在列表中追加元素、…

mysql数据库备份学习笔记

数据库备份 方法1 物理备份&#xff1a;xtrabackup 方法2 逻辑备份 mysqldump 参考备份与恢复的方法&#xff1a; 【MySql】Mysql之备份与恢复_mysql数据库备份与还原-CSDN博客 可以借鉴的物理备份&#xff1a; 思路是 先做一次全量备份&#xff0c;然后每天做一次增量备份…

Flask 专题

[CISCN2019 总决赛 Day1 Web3]Flask Message Board 查看session解密 但不知道密钥&#xff0c;题目说FLASK,那肯定就是找密钥,发现输入什么都没有显示&#xff0c;只有author那里有回显在版上&#xff0c;所以尝试sstl&#xff0c;{{config}}找到密钥 扫目录发现有admin进入…

AttributeError: cannot assign module before Module.__init__() call

原因 调用了自定义的类&#xff0c;但是在自定义的类的__init__函数下面没有写super( XXX, self ).init() 错误案例 import torch import torch.nn as nnclass SelfAttention(nn.Module):""" Self-Attention """def __init__(self, n_head, d…

四、MySQL

MySQL MySQL1.初识网站2.安装MySQL2.1 下载&#xff08;最重要的一点是路径中不能有中文&#xff0c;哪怕是同级目录也不行&#xff09;2.2安装补丁2.3安装2.4创建配置文件2.5初始化 3.启动MySQL4.连接测试4.1 设置密码4.2 查看已有的文件夹&#xff08;数据库&#xff09;4.3 …

深入浅出:Objective-C中使用MWFeedParser下载豆瓣RSS

摘要 本文旨在介绍如何在Objective-C中使用MWFeedParser库下载豆瓣RSS内容&#xff0c;同时展示如何通过爬虫代理IP技术和多线程提高爬虫的效率和安全性。 背景 随着信息量的激增&#xff0c;爬虫技术成为了获取和处理大量网络数据的重要手段。Objective-C作为一种成熟的编程…

速卖通安全测评补单技术提升运营安全性

对于一个新品来说&#xff0c;最大的问题就是评论。没有评论&#xff0c;你的广告就不能打的很靠前&#xff0c;那样你的转化率就会非常低&#xff0c;数据也很差。新品运气不好的来两个一星差评&#xff0c;链接可能就此废掉&#xff0c;做不上去了。所以虽然平台管的非常的严…

使用R语言计算模拟二项分布

二项分布理论 二项分布是一种离散概率分布&#xff0c;描述了在n次独立重复的伯努利试验中成功的次数的概率分布。其中&#xff0c;每次试验的结果只有两个可能&#xff1a;成功或失败&#xff0c;且每次试验的成功概率p是相同的。 具体来说&#xff0c;如果随机变量X表示在n次…

牛牛的凑数游戏 --- 题解

目录 牛牛的凑数游戏&#xff1a; 题目大意&#xff1a; 思路解析&#xff1a; 代码实现&#xff1a; 牛牛的凑数游戏&#xff1a; 题目大意&#xff1a; 思路解析&#xff1a; 我们可以很容易一个区间是否会存在1&#xff0c;那么我们想如果存在1&#xff0c;且有3个1&…

HANA VIEW 用 ABAP 创建CDS VIEW,在生成ODATA

这里我们做ADT来创建 场景介绍&#xff1a;把hana中的一个底表&#xff0c;创建成ABAP的 CDS VIEW &#xff0c;在把CDS VIEW 生成 OData 服务。 一、创建CDS Table Function 红框内根据自身情况填写 选择 Define Table Function with Parameters 创建 Data Definition 完整…