spring 组件 扫描

2023-11-13

@ComponentScan(basePackages = {“com”})

组件扫描
@ComponentScan等价于
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.scan("com");


模拟包扫描

获取项目真实路径
File file =new File(RealPath)
String[] files= file.list()
clazz = files.for(file.split(.class)[0])
class.forname(clazz)




扫描当前包及其子包

在这里插入图片描述

在这里插入图片描述

根据spring的包表达式进行扫描 classpath*:/com/**/*.class

  • Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);

由源码可见Spring提供了一个资源扫描的类 可以根据spring的包表达式进行扫描


  PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
        try {
            Resource[] resource = resolver.getResources("classpath*:/com/atsun/**/*.class");
            for (int i = 0; i < resource.length; i++) {
                
                System.out.println(resource[i].getFilename()+"---------------");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }



或者

PathMatchingResourcePatternResolver resolver = (PathMatchingResourcePatternResolver)ResourcePatternUtils.getResourcePatternResolver(null);
 try {
     Resource[] resource = resolver.getResources("classpath*:/com/atsun/**/*.class");
     for (int i = 0; i < resource.length; i++) {

         System.out.println(resource[i].getFilename()+"---------------");
     }
 } catch (IOException e) {
     e.printStackTrace();
 }

在这里插入图片描述
TypeFilter

在这里插入图片描述
这里添加的typefilter
org.springframework.context.annotation.ComponentScanAnnotationParser#parse
在这里插入图片描述
确定加了@Compent注解后

  • ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);

在这里插入图片描述
再判断是否有资格成为候选类,由就添加进候选集合
这也就是为什么接口上加了@Component注解还是无法扫描进容器的原因
在这里插入图片描述+ 添加进候选集合
在这里插入图片描述

由源码可以看出,我们也可以借助spring的扫描器来自定义扫描路径,需要将判断条件修改成我们自己的就行了

添加自定义扫描


public class MyScanner extends ClassPathScanningCandidateComponentProvider {


    public MyScanner(){
        this.addIncludeFilter(new TypeFilter() {
            @Override
            public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
                return true;
            }
        });

    }

    protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
        AnnotationMetadata metadata = beanDefinition.getMetadata();
//	判断类是否有资格作为候选  有可能时内部类 ,接口或者抽象类,有没有加lookup
        return metadata.isInterface();
    }

}


第二种方法添加自定义扫描


@Retention(RetentionPolicy.RUNTIME)
public @interface Sunxxx {
}

public class A extends ClassPathBeanDefinitionScanner {
    public A(BeanDefinitionRegistry registry) {
        super(registry);
    }

    @Override
    protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
        AnnotationMetadata metadata = beanDefinition.getMetadata();
		只要是接口就可以
        return metadata.isInterface();

    }

}

A a = new A(context);


//private final List<TypeFilter> includeFilters = new ArrayList<>();


注册	includeFilters 
a.addIncludeFilter(new AnnotationTypeFilter(Sunxxx.class));

int com = a.scan("com");


System.out.println(com);

在这里插入图片描述
mybatis
在这里插入图片描述

  • 自定义就是改变isCandidateComponent方法的判断

再看一下是何时添加的TypeFilter --》 自定义过滤规则 CUSTOM @MapperScanner注解时就有使用
由 new AnnotationConfigApplicationContextnew —> ClassPathBeanDefinitionScanner() 一步步调用过来
在这里插入图片描述

在spring-mybatis中扫描的拓展
在这里插入图片描述
在这里插入图片描述

扫描在哪里执行的?

扫描是在执行BeanDefinitionRegistryPostProcess时执行的,进行扫描的类是他的一个子类ConfigurationClassProcess中

在创建spring应用时,先会调用父类实例化bean工厂

AnnotationConfigApplicationContext extend   GenericApplicationContext
public AnnotationConfigApplicationContext() {
	注册默认bd 
	this.reader = new AnnotatedBeanDefinitionReader(this);
	this.scanner = new ClassPathBeanDefinitionScanner(this);
}

在这里插入图片描述

这里注册默认的5个bd
在这里插入图片描述

在这里插入图片描述

在这个方法中会实例化实现了BeanDefinitionRegistryPostProcessor的类,而ConfigurationClassPostProcess就实现了这个类

org.springframework.context.support.PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors(org.springframework.beans.factory.config.ConfigurableListableBeanFactory, java.util.List<org.springframework.beans.factory.config.BeanFactoryPostProcessor>)

在这里插入图片描述

此时已经有了bd,但是还没在容器中,如果getBean的话就会去创建它
在这里插入图片描述

bean工厂后置处理器


//			ConfigurationClassPostProcessor 是唯一一个实现了BeanDefinitionRegistryPostProcessor的类
//			执行 ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry
//			这个类中完成扫描 解析注解 当解析到import时 mybatis中执行import的类的 一个方法
扫描bd {
	普通注解,
	配置类
}
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);


先获取所有的bd candidateNames  默认5+自己注册的配置类一个


else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
候选类是一个 ImportBeanDefinitionRegistrar -> 委托给它注册额外的 bean 定义
	Class<?> candidateClass = candidate.loadClass();

如果import的类 实现了ImportBeanDefinitionRegistrar接口, 主要是实例化它, 拓展点
	ImportBeanDefinitionRegistrar registrar =
			ParserStrategyUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class,
					this.environment, this.resourceLoader, this.registry);

把实例好的ImportBeanDefinitionRegistrar 放入map中  后面会循环执行
	configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
}

mybatis  就是在执行
ImportBeanDefinitionRegistrar.registerBeanDefinitions方法时,给bd中添加了一个
MapperScannerConfigurer的bd 他实现了 BeanDefinitionRegistryPostProcessor
等spring自己执行到BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry时再来完成扫描






新版中多了一个方式 可以不用@MapperScan注解了
因为MapperScannerConfigurer也实现了 BeanDefinitionRegistryPostProcessor
所以spring就会去执行他的方法
在这里插入图片描述


/**
 * customeimport.properties配置文件中的内容:
 * 		custome.importselector.expression= com.itheima.service.impl.*
 * @author 黑马程序员
 * @Company http://www.itheima.com
 */
public class CustomeImportSelector implements ImportSelector {

    private String expression;

    public CustomeImportSelector(){
        try {
            Properties loadAllProperties = PropertiesLoaderUtils.loadAllProperties("customeimport.properties");
            expression = loadAllProperties.getProperty("custome.importselector.expression");
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    /**
     * 生成要导入的bean全限定类名数组
     * @param importingClassMetadata
     * @return
     */
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        //1.定义扫描包的名称
        String[] basePackages = null;
        //2.判断有@Import注解的类上是否有@ComponentScan注解
        if (importingClassMetadata.hasAnnotation(ComponentScan.class.getName())) {
            //3.取出@ComponentScan注解的属性
            Map<String, Object> annotationAttributes = importingClassMetadata.getAnnotationAttributes(ComponentScan.class.getName());
            //4.取出属性名称为basePackages属性的值
            basePackages = (String[]) annotationAttributes.get("basePackages");
        }
        //5.判断是否有此属性(如果没有ComponentScan注解则属性值为null,如果有ComponentScan注解,则basePackages默认为空数组)
        if (basePackages == null || basePackages.length == 0) {
            String basePackage = null;
            try {
                //6.取出包含@Import注解类的包名
                basePackage = Class.forName(importingClassMetadata.getClassName()).getPackage().getName();
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
            //7.存入数组中
            basePackages = new String[] {basePackage};
        }
        //8.创建类路径扫描器
        ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(false);
        //9.创建类型过滤器(此处使用切入点表达式类型过滤器)
        TypeFilter typeFilter = new AspectJTypeFilter(expression,this.getClass().getClassLoader());
        //10.给扫描器加入类型过滤器
        scanner.addIncludeFilter(typeFilter);
        //11.创建存放全限定类名的集合
        Set<String> classes = new HashSet<>();
        //12.填充集合数据
        for (String basePackage : basePackages) {
            scanner.findCandidateComponents(basePackage).forEach(beanDefinition -> classes.add(beanDefinition.getBeanClassName()));
        }
        //13.按照规则返回
        return classes.toArray(new String[classes.size()]);
    }
}



/**
 * @author 黑马程序员
 * @Company http://www.itheima.com
 */
@Configuration
@ComponentScan("com.itheima")
@Import(CustomeImportDefinitionRegistrar.class)
public class SpringConfiguration {
}

/**
 * 自定义bean导入注册器
 * @author 黑马程序员
 * @Company http://www.itheima.com
 */
public class CustomeImportDefinitionRegistrar implements ImportBeanDefinitionRegistrar {

    private String expression;

    public CustomeImportDefinitionRegistrar(){
        try {
            Properties loadAllProperties = PropertiesLoaderUtils.loadAllProperties("customeimport.properties");
            expression = loadAllProperties.getProperty("custome.importselector.expression");
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }


    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        //1.定义扫描包的名称
        String[] basePackages = null;
        //2.判断有@Import注解的类上是否有@ComponentScan注解
        if (importingClassMetadata.hasAnnotation(ComponentScan.class.getName())) {
            //3.取出@ComponentScan注解的属性
            Map<String, Object> annotationAttributes = importingClassMetadata.getAnnotationAttributes(ComponentScan.class.getName());
            //4.取出属性名称为basePackages属性的值
            basePackages = (String[]) annotationAttributes.get("basePackages");
        }
        //5.判断是否有此属性(如果没有ComponentScan注解则属性值为null,如果有ComponentScan注解,则basePackages默认为空数组)
        if (basePackages == null || basePackages.length == 0) {
            String basePackage = null;
            try {
                //6.取出包含@Import注解类的包名
                basePackage = Class.forName(importingClassMetadata.getClassName()).getPackage().getName();
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
            //7.存入数组中
            basePackages = new String[] {basePackage};
        }
        //8.创建类路径扫描器
        ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(registry, false);
        //9.创建类型过滤器(此处使用切入点表达式类型过滤器)
        TypeFilter typeFilter = new AspectJTypeFilter(expression,this.getClass().getClassLoader());
        //10.给扫描器加入类型过滤器
        scanner.addIncludeFilter(typeFilter);
        //11.扫描指定包
        scanner.scan(basePackages);
    }
}



本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

spring 组件 扫描 的相关文章

  • 我需要在 Spring 中检查每个控制器中的有效会话吗? [关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 假设在 Spring Mvc 的 Web 应用程序中 我们是否需要检查每个控制器或 jsps 中的有效会话 我该如何解决 MVC 中的
  • 解决错误:日志已在具有多个实例的atomikos中使用

    我仅在使用atomikos的实时服务器上遇到问题 在我的本地服务器上它工作得很好 我在服务器上面临的问题是 init 中出错 日志已在使用中 完整的异常堆栈跟踪 java lang RuntimeException Log already
  • ExceptionConverter:java.io.IOException:文档没有页面。我正在使用 iText

    当我执行下面的代码时 File f new File c sample pdf PdfWriter getInstance document new FileOutputStream f document open System out p
  • IntelliJ IDEA 创建的 JAR 文件无法运行

    我在 IntelliJ 中编写了一个跨越几个类的程序 当我在 IDE 中测试它时它运行良好 但是 每当我按照教程将项目制作成 jar 可执行文件时 它就不会运行 双击 out 文件夹中的文件时 该文件不会运行 并显示 无法启动 Java J
  • CXF Swagger2功能添加安全定义

    我想使用 org apache cxf jaxrs swagger Swagger2Feature 将安全定义添加到我的其余服务中 但是我看不到任何相关方法或任何有关如何执行此操作的资源 下面是我想使用 swagger2feature 生成
  • 使用 ANTLR 为 java 源代码生成抽象语法树

    如何使用 ANTLR 从 java src 代码生成 AST 有什么帮助吗 好的 步骤如下 前往ANTLR站点 http www antlr org 并下载最新版本 下载Java g和JavaTreeParser g文件来自here htt
  • Convert.FromBase64String 方法的 Java 等效项

    Java 中是否有相当于Convert FromBase64String http msdn microsoft com en us library system convert frombase64string aspx which 将指
  • Prim 的迷宫生成算法:获取相邻单元格

    我基于 Prim 算法编写了一个迷宫生成器程序 该算法是 Prim 算法的随机版本 从充满墙壁的网格开始 选择一个单元格 将其标记为迷宫的一部分 将单元格的墙壁添加到墙壁列表中 While there are walls in the li
  • Spring引导@Transactional

    spring boot会自动在controller层添加 Transactional注解吗 我尝试将 Transactional 放在服务层 但似乎控制器层覆盖了注释 我有这个配置
  • 请求位置更新参数

    这就是 requestLocationUpdates 的样子 我使用它的方式 requestLocationUpdates String provider long minTime float minDistance LocationLis
  • 迁移到 java 17 后有关“每个进程的内存映射”和 JVM 崩溃的 GC 警告

    我们正在将 java 8 应用程序迁移到 java 17 并将 GC 从G1GC to ZGC 我们的应用程序作为容器运行 这两个基础映像之间的唯一区别是 java 的版本 例如对于 java 17 版本 FROM ubuntu 20 04
  • 序列化对象以进行单元测试

    假设在单元测试中我需要一个对象 其中所有 50 个字段都设置了一些值 我不想手动设置所有这些字段 因为这需要时间而且很烦人 不知何故 我需要获得一个实例 其中所有字段都由一些非空值初始化 我有一个想法 如果我要调试一些代码 在某个时候我会得
  • 如何将文件透明地传输到浏览器?

    受控环境 IE8 IIS 7 ColdFusion 当从 IE 发出指向媒体文件 例如 mp3 mpeg 等 的 GET 请求时 浏览器将启动关联的应用程序 Window Media Player 我猜测 IIS 提供文件的方式允许应用程序
  • 如何在 JFreeChart TimeSeries 图表上显示降雨指数和温度?

    目前 我的 TimeSeries 图表每 2 秒显示一个位置的温度 现在 如果我想每2秒显示一次降雨指数和温度 我该如何实现呢 这是我的代码 import testWeatherService TestWeatherTimeLapseSer
  • org.jdesktop.application 包不存在

    几天以来我一直在构建一个 Java 桌面应用程序 一切都很顺利 但是今天 当我打开Netbeans并编译文件时 出现以下编译错误 Compiling 9 source files to C Documents and Settings Ad
  • 将 JSON 参数从 java 发布到 sinatra 服务

    我有一个 Android 应用程序发布到我的 sinatra 服务 早些时候 我无法读取 sinatra 服务上的参数 但是 在我将内容类型设置为 x www form urlencoded 之后 我能够看到参数 但不完全是我想要的 我在
  • 查看Jasper报告执行的SQL

    运行 Jasper 报表 其中 SQL 嵌入到报表文件 jrxml 中 时 是否可以看到执行的 SQL 理想情况下 我还想查看替换每个 P 占位符的值 Cheers Don JasperReports 使用 Jakarta Commons
  • KeyPressed 和 KeyTyped 混淆[重复]

    这个问题在这里已经有答案了 我搜索过之间的区别KeyPressedand KeyTyped事件 但我仍然不清楚 我发现的一件事是 Keypressed 比 KeyTyped 首先被触发 请澄清一下这些事件何时被准确触发 哪个适合用于哪个目的
  • java8 Collectors.toMap() 限制?

    我正在尝试使用java8Collectors toMap on a Stream of ZipEntry 这可能不是最好的想法 因为在处理过程中可能会发生异常 但我想这应该是可能的 我现在收到一个我不明白的编译错误 我猜是类型推理引擎 这是
  • javax.persistence.Table.indexes()[Ljavax/persistence/Index 中的 NoSuchMethodError

    我有一个 Play Framework 应用程序 并且我was使用 Hibernate 4 2 5 Final 通过 Maven 依赖项管理器检索 我决定升级到 Hibernate 4 3 0 Final 成功重新编译我的应用程序并运行它

随机推荐

  • html5 颜色随机变化,每次在HTML5 Canvas的.fillStyle中使用时,将画布图案随机化为不同的颜色(randomizing a canvas pattern to be a diff...

    每次在HTML5 Canvas的 fillStyle中使用时 将画布图案随机化为不同的颜色 randomizing a canvas pattern to be a different color every time it is used
  • 文本数据导入HBASE库找不到类com/google/common/collect/Multimap

    文本数据导入HBASE库找不到类com google common collect Multimap 打算将文本文件导入HBASE库 在运行命令的时候找不到类 com google common collect Multima hadoop
  • PyTorch实战使用Resnet迁移学习

    PyTorch实战使用Resnet迁移学习 项目结构 项目任务 项目代码 网络模型测试 项目结构 数据集存放在flower data文件夹 cat to name json是makejson文件运行生成的 TorchVision文件主要存放
  • springboot 整合 mongodb

    前言 前面通过 5 节的内容 我们学习了 mongodb 的使用 这节我们通过学过的知识运用 springboot 整合 mongodb 搭建一个小项目 项目搭建 springboot 基于 maven 项目搭建的具体过程这里就不再赘述了
  • style标签上的scoped属性

    vue中 在vue文件中的style标签上有一个特殊的属性 scoped 布尔值 作用 该属性的作用是将当前标签下的样式私有化 仅对当前组件起作用 只管当前组件和子组件的最外层 不控制自组件 原理 若是给style标签添加了scoped属性
  • 【python与数据分析】Python与数据分析概述

    目录 一 认识数据分析 1 数据分析的方法论与数据分析方法 一 七何分析法 建立框架 二 演绎树分析法 问题分层 三 PEST分析法 设计环境 四 金字塔原理分析法 建立逻辑 五 4P营销理论分析法 业务指导 六 SWOT分析法 战略竞争
  • 计算机专业大二了啥都没学怎么办

    如果您是计算机专业的大二学生 但是还没有学到很多内容 那么您可以考虑以下几点 加强自学 首先 您可以自学一些基本的计算机知识 如操作系统 算法 数据结构等 寻找资源 您可以寻找一些在线的学习资源 如课程 书籍 视频等 加深自己的知识储备 向
  • C语言函数递归例题讲解(超详细~)

    文章目录 递归题型讲解 例题1 例题2 例题3 递归题型讲解 例题1 根据下面递归函数 调用函数Fun 2 返回值是多少 int Fun int n if n 5 return 2 else return 2 Fun n 1 A 2 B 4
  • fit_transform含义

    fit transform X train 找出X train的均值和 标准差 并应用在X train上 对于X test 直接使用transform方法 此时StandardScaler已经保存了X train的均值和标准差
  • telnet 查看端口是否可访问

    1 首先为什么要写这篇文章 说到为什么还得从DNS服务器说起 我在我的电脑上安装了DNS服务器 但是用网络去访问还怎么都访问都不上去 于是我就打开dos窗口 用ping命令查看是否可以ping 如 ping 125 34 49 211 通
  • FANUC机器人程序实例

    FANUC机器人程序实例 PS 1 2 2 3 7 8 8 9 9 10 10 7为圆弧运动 6 1 3 4 4 5 5 6 6 7 7 6 为直线运动 先画图1 循环3次 等待3秒 再画图2 轨迹如上图所示 10个位置在同一平面 程序 位
  • linux配置SSH

    目录 一 ssh简介 二 ssh配置文件 三 ssh远程登录 四 ssh远程登录原理 4 1 对称加密 4 3非对称加密 一 ssh简介 SSH为建立在应用层上的安全协议 SSH是目前非常可靠 专门为远程登录会话和其它网了服务提供安全性的协
  • 程序员微信名昵称_微信营销手段之昵称命名

    这段时间 我玩微信玩的不少 但是主要还是把精力放在我的QQ空间了 但是我不管在微信上还是扣扣空间我都发现了一个怪现象 就是一直有人用广告名称做昵称 啥是广告名字呢 比如她是卖化妆品的 然后她就把微信昵称改成了某某化妆品销售 代购什么的 这种
  • 史上最全Unity3D游戏开发教程,从入门到精通(含学习路线图)

    Unity现在已经用的很广泛啦 可是却一直没有什么美术向的教程 程序员方面的内容在各个论坛都有讨论 但是美术似乎很弱势啊 明明美术也很需要掌握引擎方面的内容嘛 山谷里的野百合还有春天呢 我们美术也要出教程 很多同学想学习unity却不知道怎
  • react中背景图片和图片引入的方法

    有三种引入背景图片的方法 1 div 2 先import引入图片路径 再用es6语法中的 引用 import bgImage from assets images bgImage webp div 3 用require进行路径引用requi
  • 【图像增强】Debiased Subjective Assessment of Real-World Image Enhancement

    最近学习了CVPR2021的一篇文章 真实世界图像增强的去偏主观质量评价 Debiased Subjective Assessment of Real World Image Enhancement 一 前言 图像质量评价 Image Qu
  • 【Keras】TensorFlow分布式训练

    当我们拥有大量计算资源时 通过使用合适的分布式策略 我们可以充分利用这些计算资源 从而大幅压缩模型训练的时间 针对不同的使用场景 TensorFlow 在 tf distribute Strategy 中为我们提供了若干种分布式策略 使得我
  • R语言相关关系可视化函数梳理

    点击蓝字关注这个神奇的公众号 作者 赵镇宁 R语言中文社区特约作者 当考察多个变量间的相关关系时 通常将多个变量的两两关系以矩阵的形式排列起来 R提供了散点图矩阵 相关矩阵等多种可视化方案 囊括了众多函数 本文对R语言相关关系可视化的函数进
  • iOS开发笔记--识别单击还是双击

    在视图上同时识别单击手势和双击手势的问题在于 当检测到一个单击操作时 无法确定是确实是一个单击操作或者只是双击操作中的第一次点击 解决这个问题的方法就是 在检测到单击时 需要等一段时间等待第二次点击 如果没有第二次点击 则为单击操作 如果有
  • spring 组件 扫描

    ComponentScan basePackages com 组件扫描 ComponentScan等价于 AnnotationConfigApplicationContext context new AnnotationConfigAppl