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

一 定义方法

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

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

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

二 ResourcePatternResolver

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

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

  1. /**
  2. * 用于查找匹配classpath下所有的匹配Resource
  3. */
  4. String CLASSPATH_ALL_URL_PREFIX = "classpath*:";
  5.  
  6. /**
  7. * 用于根据传入的locationPattern查找和其匹配的Resource实例,并以数组的形式返回,在返回的数组中不可以存在
  8. * 相同的Resource实例
  9. */
  10. 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()方法:

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

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的接口定义如下:

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

PathMatchingResourcePatternResolver中getResources方法的实现:

  1. @Override
  2. public Resource[] getResources(String locationPattern) throws IOException {
  3. Assert.notNull(locationPattern, "Location pattern must not be null");
  4. //判断是否是classpath*: 开头的位置,表示需要匹配多个,即不同目录下相同名字的文件
  5. if (locationPattern.startsWith(CLASSPATH_ALL_URL_PREFIX)) { //
  6. // 判断是否包含通配符
  7. if (getPathMatcher().isPattern(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length()))) {
  8. // 查找所有匹配名称的resource
  9. return findPathMatchingResources(locationPattern);
  10. }
  11. else {
  12. //查找所有该名称的resource,不同目录里的
  13. return findAllClassPathResources(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length()));
  14. }
  15. }
  16. else {
  17. //获取截取前缀长度
  18. int prefixEnd = (locationPattern.startsWith("war:") ? locationPattern.indexOf("*/") + 1 :
  19. locationPattern.indexOf(':') + 1);
  20. if (getPathMatcher().isPattern(locationPattern.substring(prefixEnd))) {
  21. // 查找所有匹配名称的resource
  22. return findPathMatchingResources(locationPattern);
  23. }
  24. else {
  25. //直接获取一个resource
  26. return new Resource[] {getResourceLoader().getResource(locationPattern)};
  27. }
  28. }
  29. }

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. 一天入门 Python 的一些心得

    1. 前言 好久没写文了.最近在搞一些好玩的技术用到了 Python .我原以为要花些时日,谁知道第一天入门之后便没有再刻意地去学习它了.这里就写写其中的一些关键点吧.如果我去学一门语言不是因为它火了 ...

  2. [UWP]XAML中的响应式布局技术

    响应式布局的概念是一个页面适配多个终端及不同分辨率.在针对特定屏幕宽度优化应用 UI 时,我们将此称为创建响应式设计.WPF设计之初响应式设计的概念并不流行,那时候大部分网页设计师都按着宽度960像素 ...

  3. 从头学pytorch(十四):lenet

    卷积神经网络 在之前的文章里,对28 X 28的图像,我们是通过把它展开为长度为784的一维向量,然后送进全连接层,训练出一个分类模型.这样做主要有两个问题 图像在同一列邻近的像素在这个向量中可能相距 ...

  4. ENS 域名注册表智能合约(ENSRegistry.sol)解析

    ENS 注册表合约是 ENS 系统中的核心合约,了解这个合约可以敲开我们理解 ENS 域名系统的大门. 打开下面的折叠区域可以查看用 Solidity 语言编写的详细代码.当前部署在以太坊中的 ENS ...

  5. 【转】Spring面试问题集锦

    Q. 对于依赖倒置原则(Dependency Inversion Principle,DIP),依赖注入(Dependency Injection,DI)和控制反转(Inversion of Cont ...

  6. vPlayer 模块Demo

    本文出自APICloud官方论坛 vPlayer iOS封装了AVPlayer视频播放功能(支持音频播放).iOS 平台上支持的视频文件格式有:WMV,AVI,MKV,RMVB,RM,XVID,MP4 ...

  7. 分享一款基于aui框架的图文发布界面

    本文出自APICloud官方论坛, 感谢论坛版主 川哥哥 的分享. 分享一款基于aui框架的图文发布界面,可以添加多张图可以删除,类似qq空间发布说说,没做服务器后端,只演示前端操作.需要用到UIMe ...

  8. 状态压缩 hdu #10

    You are playing CSGO. There are n Main Weapons and m Secondary Weapons in CSGO. You can only choose ...

  9. FileUpload的控件上传excel

    在一个使用FileUpload的控件上传excel,读取excel的数据 因为上传的路径一直被限定在C:\Program\IIS\Express 一直限制这个文件下, 想要解决这个问题. 在谷歌浏览器 ...

  10. 前端笔记5-js1

    一.在JS中一共有6种数据类型1. String 字符串2. Number 数值3. Boolean 布尔值4. Null 空值5. Undefined 未定义6. Object 对象 其中 Stri ...