参考博客: https://www.cnblogs.com/jixp/articles/10702486.html

一 定义方法

Spring提供了ResourceLoader接口用于实现不同的Resource加载策略,即将不同Resource实例的创建交给ResourceLoader来计算.

接口提供了两个方法和一个字符串常量:

    /**  class path: "classpath:". */
String CLASSPATH_URL_PREFIX = ResourceUtils.CLASSPATH_URL_PREFIX; /**
* 通过提供的资源location参数获取Resource实例,该实例可以是ClasPathResource、FileSystemResource、UrlResource等,
* 但是该方法返回的Resource实例并不保证该Resource一定是存在的,需要调用exists方法判断
*/
Resource getResource(String location); /**
* 此方法将ClassLoader暴露出来,可以直接调用getClassLoader()方法获得ClassLoader,而不是依赖于Thread Context ClassLoader,
* 因为有些时候ResourceLoader内部使用自定义的ClassLoader
*/
@Nullable
ClassLoader getClassLoader();

二 ResourcePatternResolver

在实际开发中经常会遇到需要通过某种匹配方式查找资源,比如通配符,而且可能有多个资源匹配这种模式,在Spring中提供了ResourcePatternResolver接口用于实现这种需求并实现了ResourceLoader接口:

接口定义了一个方法和一个正则字符串常量:

    /**
* 用于查找匹配classpath下所有的匹配Resource
*/
String CLASSPATH_ALL_URL_PREFIX = "classpath*:"; /**
* 用于根据传入的locationPattern查找和其匹配的Resource实例,并以数组的形式返回,在返回的数组中不可以存在
* 相同的Resource实例
*/
Resource[] getResources(String locationPattern) throws IOException;

三 实现类

ResourceLoader接口的实现类在spring中有DefaultResourceLoader、FileSystemResourceLoader和ServletContextResourceLoader等.

ResourcePatternResolver接口的实现类有PathMatchingResourcePatternResolver。并且ApplicationContext接口也继承了ResourcePatternResolver,

在实现中,ApplicationContext的实现类会将逻辑代理给相关的单独实现类,如PathMatchingResourcePatternResolver等。在ApplicationContext中ResourceLoaderAware接口,可以将ResourceLoader(自身)注入到实现该接口的Bean中,

在Bean中可以将其强制转换成ResourcePatternResolver接口使用(为了安全,强转前需要判断)。

1 DefaultResourceLoader

DefaultResourceLoader是ResourceLoader的默认实现,AbstractApplicationContext继承该类。主要是实现了ResourceLoader的getResource()方法:

    @Override
public Resource getResource(String location) {
Assert.notNull(location, "Location must not be null");
/**
* protocolResolvers:是类的成员变量,ProtocolResolver类的Set集合
* ProtocolResolver是解析location的自定义拓展类接口,只定义了resolve解析方法,根据传入的location字符串,解析出对应的Resource资源
* 我们可以自定义一个类实现ProtocolResolver接口,然后实现该resolve方法,就可以解析特定的location得到Resoure。
* 这一步主要是看是否有自定义的协议解析可以解析出Resource对象,如果有就返回这个实例
*/
for (ProtocolResolver protocolResolver : this.protocolResolvers) {
Resource resource = protocolResolver.resolve(location, this);
if (resource != null) {
return resource;
}
}
//返回ClassPathContextResource实例
if (location.startsWith("/")) {
return getResourceByPath(location);
}
/**
* 如果是 classpath开头,返回ClassPathResource实例
* 开发中一般在这返回配置文件实例,比如 new ClassPathXmlApplicationContext("classpath:spring.xml");
*/
else if (location.startsWith(CLASSPATH_URL_PREFIX)) {
return new ClassPathResource(location.substring(CLASSPATH_URL_PREFIX.length()), getClassLoader());
}
else {
try {
/**
* 尝试创建UrlResource,如果当前location没有定义URL的协议(即以”file:”、”zip:”等开头,比如使用相对路径”resources/META-INF/MENIFEST.MF),
* 则创建UrlResource会抛出MalformedURLException,
* 此时调用getResourceByPath()方法获取Resource实例
*/
URL url = new URL(location);
return (ResourceUtils.isFileURL(url) ? new FileUrlResource(url) : new UrlResource(url));
}
catch (MalformedURLException ex) {
// No URL -> resolve as resource path.
return getResourceByPath(location);
}
}
}

2 FileSystemResourceLoader

FileSystemResourceLoader继承了DefaultResourceLoader,覆写了getResourceByPath()方法,

DefaultResourceLoader的getResourceByPath方法返回的是ClassPathContextResource实例,而返回的是FileSystemContextResource实例.

3 ServletContextResourceLoader

ServletContextResourceLoader类也继承自DefaultResourceLoader,和FileSystemResourceLoader一样,它的getResource方法的实现逻辑和DefaultResourceLoader相同,

不同的是它实现了自己的getResourceByPath方法,即当UrlResource创建失败时,它会使用ServletContextResource实例:

4 PathMatchingResourcePatternResolver

PathMatchingResourcePatternResolver类实现了ResourcePatternResolver接口,它包含了对ResourceLoader接口的引用,在对继承自ResourceLoader接口的方法的实现会代理给该引用,

同时在getResources()方法实现中,当找到一个匹配的资源location时,可以使用该引用解析成Resource实例。默认使用DefaultResourceLoader类,用户可以使用构造函数传入

自定义的ResourceLoader。

PathMatchingResourcePatternResolver还包含了一个对PathMatcher接口的引用,该接口基于路径字符串实现匹配处理,如判断一个路径字符串是否包含通配符(’*’、’?’),

判断给定的path是否匹配给定的pattern等。Spring提供了AntPathMatcher对PathMatcher的默认实现,表达该PathMatcher是采用Ant风格的实现。

其中PathMatcher的接口定义如下:

    //判断path是否是一个pattern,即判断path是否包含通配符
boolean isPattern(String path); //判断给定path是否可以匹配给定pattern
boolean match(String pattern, String path); //判断给定path是否可以匹配给定pattern,该方法不同于match,它只是做部分匹配,即当发现给定path匹配给定path的可能性比较大时,即返回true。
// 可以先使用它确定需要全面搜索的范围,然后在这个比较小的范围内再找出所有的资源文件全路径做匹配运算
boolean matchStart(String pattern, String path); //去除path中和pattern相同的字符串,只保留匹配的字符串。
// 比如如果pattern为”/doc/csv/*.htm”,而path为”/doc/csv/commit.htm”,则该方法的返回值为commit.htm。
//该方法默认pattern和path已经匹配成功,因而算法比较简单
String extractPathWithinPattern(String pattern, String path);

PathMatchingResourcePatternResolver中getResources方法的实现:

    @Override
public Resource[] getResources(String locationPattern) throws IOException {
Assert.notNull(locationPattern, "Location pattern must not be null");
//判断是否是classpath*: 开头的位置,表示需要匹配多个,即不同目录下相同名字的文件
if (locationPattern.startsWith(CLASSPATH_ALL_URL_PREFIX)) { //
// 判断是否包含通配符
if (getPathMatcher().isPattern(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length()))) {
// 查找所有匹配名称的resource
return findPathMatchingResources(locationPattern);
}
else {
//查找所有该名称的resource,不同目录里的
return findAllClassPathResources(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length()));
}
}
else {
//获取截取前缀长度
int prefixEnd = (locationPattern.startsWith("war:") ? locationPattern.indexOf("*/") + 1 :
locationPattern.indexOf(':') + 1);
if (getPathMatcher().isPattern(locationPattern.substring(prefixEnd))) {
// 查找所有匹配名称的resource
return findPathMatchingResources(locationPattern);
}
else {
//直接获取一个resource
return new Resource[] {getResourceLoader().getResource(locationPattern)};
}
}
}

springIOC源码接口分析(六):ResourceLoader的更多相关文章

  1. springIOC源码接口分析(九):Environment

    先贴一下接口继承关系图,spring容器启动的时候会初始化环境,所以此接口相关接口非常有必要进行了解: 一 PropertyResolver接口 Environment继承了该接口,PropertyR ...

  2. springIOC源码接口分析(三):ApplicationContext

    一 新增方法 主要都是获取容器基本信息的一些接口,比如获取名称,id和启动时间戳,获取AutowireCapableBeanFactory等接口 二 继承接口 ApplicationContext继承 ...

  3. springIOC源码接口分析(八):AutowireCapableBeanFactory

    参考博文: https://blog.csdn.net/f641385712/article/details/88651128 一 接口规范 从宏观上看,AutowireCapableBeanFact ...

  4. springIOC源码接口分析(十一):ConfigurableApplicationContext

    一 实现接口 关系图: ConfigurableApplicationContext接口实现了三个接口,ApplicationContext, Lifecycle, Closeable, Applic ...

  5. springIOC源码接口分析(七):ApplicationEventPublisher

    一 定义方法 此接口主要是封装事件发布功能的接口,定义了两个方法: /** * 通知应用所有已注册且匹配的监听器此ApplicationEvent */ default void publishEve ...

  6. springIOC源码接口分析(五):ListableBeanFactory

    一 继承关系 该接口是对BeanFactory的扩展,允许预加载bean定义的BeanFactory可以实现此接口 其目的在于使实现它的BeanFactory能够枚举所有的Bean 该接口不支持分层结 ...

  7. springIOC源码接口分析(四):MessageSource

    一 定义方法 MessageSource接口用于支持信息的国际化和包含参数的信息的替换 这个接口定义了三个方法: public interface MessageSource { /** * 解析co ...

  8. springIOC源码接口分析(二):ConfigurableBeanFactory

    一 继承功能 1 SingletonBeanRegistry接口 此接口是针对Spring中的单例Bean设计的.提供了统一访问单例Bean的功能,类中定义了以下方法: 2 HierarchicalB ...

  9. springIOC源码接口分析(一):BeanFactory

    一 应用场景 BeanFactory接口定义了IOC容器的最基本功能,提供了容器应该具有的功能规范,所有的容器都应该实现这个接口 BeanFactory设计了getBean方法用来获取容器中的Bean ...

随机推荐

  1. 为什么使用kotlin可以节省开发时间

    前言:.kotlin是一门语言,光靠一篇文章要入门不太现实,所以这篇文章重点讲的是kotlin相对于java的一些特性和这些特性带来的好处. 一.简单介绍 Kotlin 是一种在 Java 虚拟机上运 ...

  2. $bzoj4152\ The\ Captain$ 最短路

    正解:最短路+优化连边 解题报告: 传送门$w$ 这种优化连边啥的真的好妙噢$QwQ$ 首先显然离散化下不说$QwQ$.然后对所有横坐标纵坐标分别建点,相邻两横坐标点相连,边权为离散前的坐标差.纵坐标 ...

  3. $bzoj4722$ 由乃 搜索

    正解:搜索 解题报告: 传送门$QwQ$ 首先发现长度为$len$的子集的值域为$[0,v\cdot len+len]$,数量为$2^{len}$.所以当$2^{len}\geq v\cdot len ...

  4. 双系统,重装windows 无法进入Windows安装界面

    解决办法 windows引导并没有被更新 进入linux 更新grub sudo update-grub 然后重启电脑,进行下一步安装 原理 grub是引导操作系统的程序,它会根据自己的配置文件,去引 ...

  5. 洛谷P1028 数的计算 题解 动态规划入门题

    题目链接:https://www.luogu.com.cn/problem/P1028 题目描述 我们要求找出具有下列性质数的个数(包含输入的自然数 \(n\) ): 先输入一个自然数 \(n(n \ ...

  6. Java网络编程——TCP图片上传

    1.编写一个服务器端程序,用来接收图片.创建一个监听指定端口号的ServerSocket服务端对象,在while(true)无限循环中持续调用ServerSocket的accept()方法来接收客户端 ...

  7. HR系列GPS北斗时间同步服务器在电力系统典型应用

    HR系列GPS北斗时间同步服务器在电力系统典型应用 时间同步系统主要由主时钟.若干从时钟.时间信号传输介质组成.根据时间同步现场的不同要求,时间同步系统的结构配置有多种形式,主要分为三种:基本式.主从 ...

  8. 27.openpyxl 向指定单元格添加图片并修改图片大小 以及修改单元格行高列宽

    openpyxl 向指定单元格添加图片并修改图片大小 以及修改单元格行高列宽 from openpyxl import Workbook,load_workbook from openpyxl.dra ...

  9. # "可插拔式"组件设计,领略组件开发的奥秘

    从一个 Confirm 组件开始,一步步写一个可插拔式的组件. 处理一个正常的支付流程(比如支付宝购买基金) 点击购买按钮 如果风险等级不匹配则:弹确认框(Confirm) 用户确认风险后:弹出支付方 ...

  10. javaScript类型和对象

    javaScript基本数据类型 Undefined: Null: Boolean: String: Number: Symbol: Object. 注意 JavaScript 的代码 undefin ...