Spring是如何扫描包的 Spring5.x

锁定这个方法,Spring会在ClassPathScanningCandidateComponentProvider类的这个方法中进行扫描

private Set<BeanDefinition> scanCandidateComponents(String basePackage) {LinkedHashSet candidates = new LinkedHashSet();try {//这是一个处理路径的步骤替换点.为/,后缀添加his.resourcePattern: "**/*.class"String packageSearchPath = "classpath*:" + this.resolveBasePackage(basePackage) + '/' + this.resourcePattern;//这里获取所有的类Resource[] resources = this.getResourcePatternResolver().getResources(packageSearchPath);boolean traceEnabled = this.logger.isTraceEnabled();boolean debugEnabled = this.logger.isDebugEnabled();Resource[] var7 = resources;int var8 = resources.length;//这里Spring对所有的资源进行过滤,读取文件,然后读取该类的接口,父类,父类的接口,验证有没有包含@Component注解(被作为了接口)for(int var9 = 0; var9 < var8; ++var9) {Resource resource = var7[var9];if (traceEnabled) {this.logger.trace("Scanning " + resource);}if (resource.isReadable()) {try {MetadataReader metadataReader = this.getMetadataReaderFactory().getMetadataReader(resource);if (this.isCandidateComponent(metadataReader)) {ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);sbd.setResource(resource);sbd.setSource(resource);if (this.isCandidateComponent((AnnotatedBeanDefinition)sbd)) {if (debugEnabled) {this.logger.debug("Identified candidate component class: " + resource);}candidates.add(sbd);} else if (debugEnabled) {this.logger.debug("Ignored because not a concrete top-level class: " + resource);}} else if (traceEnabled) {this.logger.trace("Ignored because not matching any filter: " + resource);}} catch (Throwable var13) {throw new BeanDefinitionStoreException("Failed to read candidate component class: " + resource, var13);}} else if (traceEnabled) {this.logger.trace("Ignored because not readable: " + resource);}}return candidates;} catch (IOException var14) {throw new BeanDefinitionStoreException("I/O failure during classpath scanning", var14);}
}

获取所有类的步骤

修改后的路径

可以看到当前的的目录变成了/分隔的**/*.class结尾的字符串

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

Resource是Spring定义的一种表示资源的类型,如下

package org.springframework.core.io;import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.net.URL;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import org.springframework.lang.Nullable;public interface Resource extends InputStreamSource {boolean exists();default boolean isReadable() {return this.exists();}default boolean isOpen() {return false;}default boolean isFile() {return false;}URL getURL() throws IOException;URI getURI() throws IOException;File getFile() throws IOException;default ReadableByteChannel readableChannel() throws IOException {return Channels.newChannel(this.getInputStream());}long contentLength() throws IOException;long lastModified() throws IOException;Resource createRelative(String var1) throws IOException;@NullableString getFilename();String getDescription();
}

1.使用AbstractApplicationContext获取资源组

public Resource[] getResources(String locationPattern) throws IOException {return this.resourcePatternResolver.getResources(locationPattern);
}

2.使用ResourcePatternResolver来进一步处理,筛选路径的开头

public Resource[] getResources(String locationPattern) throws IOException {//一个检查是否为空的警报类Assert.notNull(locationPattern, "Location pattern must not be null");//因为我们是classpath开头的,所以会进入这里if (locationPattern.startsWith("classpath*:")) {return this.getPathMatcher().isPattern(locationPattern.substring("classpath*:".length())) ? this.findPathMatchingResources(locationPattern) : this.findAllClassPathResources(locationPattern.substring("classpath*:".length()));} else {int prefixEnd = locationPattern.startsWith("war:") ? locationPattern.indexOf("*/") + 1 : locationPattern.indexOf(58) + 1;return this.getPathMatcher().isPattern(locationPattern.substring(prefixEnd)) ? this.findPathMatchingResources(locationPattern) : new Resource[]{this.getResourceLoader().getResource(locationPattern)};}
}

这里有一些似乎迷惑的操作,讲解一下

this.getPathMatcher()这里是获取了Spring的一个工具类,是一个路径匹配的工具类,

isPattern方法是为了检查该路径是否为一个path路径,如下,包含下面几种字符就被认为是path,为了安全,这样是应该的

public boolean isPattern(@Nullable String path) {if (path == null) {return false;} else {boolean uriVar = false;for(int i = 0; i < path.length(); ++i) {char c = path.charAt(i);if (c == '*' || c == '?') {return true;}if (c == '{') {uriVar = true;} else if (c == '}' && uriVar) {return true;}}return false;}
}

现在是重头戏,正式开始找类

执行this.findPathMatchingResources(locationPattern)方法

protected Resource[] findPathMatchingResources(String locationPattern) throws IOException {//对路径进行处理,保证路径的正常String rootDirPath = this.determineRootDir(locationPattern);//取一下结尾的类型信息,其实就是**/*.classString subPattern = locationPattern.substring(rootDirPath.length());//获取资源根目录,//URL [file:/E:/你的项目文件夹/target/classes/com/hhcat/hhcat/],//涉及的不是很复杂,想了解自己debug一下就行Resource[] rootDirResources = this.getResources(rootDirPath);Set<Resource> result = new LinkedHashSet(16);Resource[] var6 = rootDirResources;int var7 = rootDirResources.length;for(int var8 = 0; var8 < var7; ++var8) {Resource rootDirResource = var6[var8];Resource rootDirResource = this.resolveRootDirResource(rootDirResource);URL rootDirUrl = ((Resource)rootDirResource).getURL();if (equinoxResolveMethod != null && rootDirUrl.getProtocol().startsWith("bundle")) {URL resolvedUrl = (URL)ReflectionUtils.invokeMethod(equinoxResolveMethod, (Object)null, new Object[]{rootDirUrl});if (resolvedUrl != null) {rootDirUrl = resolvedUrl;}rootDirResource = new UrlResource(rootDirUrl);}//一连串判断,是为了查看是什么类型的文件我们是file开头的if (rootDirUrl.getProtocol().startsWith("vfs")) {result.addAll(PathMatchingResourcePatternResolver.VfsResourceMatchingDelegate.findMatchingResources(rootDirUrl, subPattern, this.getPathMatcher()));} //走了这里,这里是实际上的扫描包,使用了File类,扫描目录下所有的以之前那个**/*.class格式的文件,然后加入在result中,完成了扫描else if (!ResourceUtils.isJarURL(rootDirUrl) && !this.isJarResource((Resource)rootDirResource)) {result.addAll(this.doFindPathMatchingFileResources((Resource)rootDirResource, subPattern));} else {result.addAll(this.doFindPathMatchingJarResources((Resource)rootDirResource, rootDirUrl, subPattern));}}if (logger.isTraceEnabled()) {logger.trace("Resolved location pattern [" + locationPattern + "] to resources " + result);}return (Resource[])result.toArray(new Resource[0]);
}

把过滤后的类返回,就完成了扫描。

Spring是如何扫描包的 Spring5.x(源码向)相关推荐

  1. 手撸Spring系列2:IOC/DI 思想(源码篇-IOC)

    说在前头: 笔者本人为大三在读学生,书写文章的目的是为了对自己掌握的知识和技术进行一定的记录,同时乐于与大家一起分享,因本人资历尚浅,发布的文章难免存在一些错漏之处,还请阅读此文章的大牛们见谅与斧正. ...

  2. Spring5.x源码分析 | 从踩坑到放弃之环境搭建

    Spring5.x源码分析--从踩坑到放弃之环境搭建 前言 自从Spring发行4.x后,很久没去好好看过Spring源码了,加上最近半年工作都是偏管理和参与设计为主,在技术细节上或多或少有点疏忽,最 ...

  3. Transformers包tokenizer.encode()方法源码阅读笔记

    Transformers包tokenizer.encode()方法源码阅读笔记_天才小呵呵的博客-CSDN博客_tokenizer.encode

  4. mysql源码包和二进制包_Linux软件包(源码包和二进制包)

    Linux下的软件包众多,且几乎都是经 GPL 授权.免费开源(无偿公开源代码)的.这意味着如果你具备修改软件源代码的能力,只要你愿意,可以随意修改. GPL,全称 General Public Li ...

  5. 微信小程序:开心锤锤超火动态表情包微信小程序源码下载自动采集

    这是一款表情包小程序源码 大家刷抖音的时候应该都刷过开心锤锤这个网红卡通短视频吧 现在这一款小程序就是和它有关的 里面的表情包呢大部分都是动态表情包(斗图的时候是不是更炫) 至于里面的表情包人物的就都 ...

  6. 第一行代码-android-第三版-pdf扫描-思维导图-课件-源码

    第一行代码-android-第三版-pdf扫描-思维导图-课件-源码 一帮公众号各种要你关注, 各种压缩包层层套娃要密码, 还要进群, 真他妈日了gou了,找了半天 分享给大家, 毫无套路! pdf扫 ...

  7. RPM包安装或者安装源码包

    在windows下安装一个软件很轻松,只要双击.exe的文件,安装提示连续"下一步"即可,然而linux系统下安装一个软件似乎并不那么轻松了,因为我们不是在图形界面下.所以你要学会 ...

  8. 易启秀20150629完整包微场景制作源码,新增1.4G素材包,全新后台UI设计+采集

    易启秀20150629完整包微场景制作源码,新增1.4G素材包,全新后台UI设计+采集 本文由 穷站长 于 2015-7-18 9:23 Saturday 发布在 php源码 评论(46) 最新版易启 ...

  9. HanLP自然语言处理包开源(包含源码)

    HanLP自然语言处理包开源(包含源码) 支持中文分词(N-最短路分词.CRF分词.索引分词.用户自定义词典.词性标注),命名实体识别(中国人名.音译人名.日本人名.地名.实体机构名识别),关键词提取 ...

最新文章

  1. R语言list.dirs函数获取目录列表实战
  2. [转]Hadoop家族学习路线图
  3. Magic Leap大举进军AR医疗:新品率先与医疗机构合作,挖走HoloLens老客户
  4. spring26-2: bean的作用域
  5. 爬虫学习笔记(二十)—— 字体反爬
  6. 【mathematical statistics】2 point estimate
  7. 大型互联网公司架构演进之路汇总
  8. oracle oemrpt数据库显现
  9. 添加底部小火箭+目录
  10. 一:HTTP协议(超详解)
  11. C# Socket简单例子(服务器与客户端通信)
  12. 燕秀工具箱图库lisp_AutoCAD模具设计插件燕秀工具箱 v2.81版(64/32bit)
  13. 湖南职称计算机模拟试题,湖南职称计算机考试培训软件:集职称计算机考试模拟题、长沙职称计算机考试题库...
  14. 我为什么放弃百词斩?
  15. 【图论】 腾讯大战360
  16. 3个步骤+1个模型,「数据分析」才是「增长黑客」的核心技能
  17. vue中使用file-saver导出文件
  18. VMW配置FusionStorage Manager(FSM)虚拟机主备
  19. 百度搜索稳定性问题分析的故事(上)
  20. jQuery 流星雨特效

热门文章

  1. 怎么把图片变成黑白?
  2. Saying Good-bye to Cambridge Again --- by Xu Zhimo 再别康桥 徐志摩
  3. java界面分割_java将一个JFrame界面分割成多部分,每部分添加独立背景图片
  4. 最近收集的一些图片(第2期)
  5. c语言数组项目按身高排序,过三关 Java冒泡排序选择排序插入排序小练习
  6. 算法竞赛入门经典 第二版 习题5-5 复合词 Compound Words uva10391
  7. Feign 调用存在的问题
  8. 微信新功能,帮你用品牌成交客户!
  9. 京东云宙斯上传单张图片php,PHP图片上传程序(单张)
  10. 2023年国漫前瞻:出海、漫改剧、元宇宙