【Java】【系列篇】【Spring源码解析】【三】【体系】【Resource体系】

主要用于加载配置资源等等

Resource

前提须知

ClassLoader类的getResource和getResourceAsStream方法是原生JDK中内置的资源加载文件的方式;Spring中资源模型顶级接口不是Resource,而是InputStreamSource接口;Spring为何自己实现一套资源加载方式?主要原因是JDK原生的URL资源加载方式,对于加载classpath或ServletContext中的资源没有标准的处理。

整体结构图(非全部)

image-20230116172022509

Spring中的资源模型

InputStreamSource

InputStreamSource接口只有一个getInputStream方法,实现了该接口的实现类都可以从中获取资源的输入流

image-20230116174909683

Resource

Resource是InputStreamSource的子接口,它是从底层资源的实际类型(例如文件或类路径资源)中抽象出来的资源描述符的接口,它代表的是可读的资源。

image-20230116175104929

EncodedResource

从类名可以看出它是编码后的资源,它的内部有个Resource类型的属性,说明它本身不是直接加载资源的

image-20230116175139984

ContextResource

ContextResource是从一个封闭的上下文中加载的资源(类似于ServletContext这种)的扩展接口,例如来自javax.servlet.ServletContext,也可以来自普通的类路径路径或相对的文件系统路径(在没有显式前缀的情况下指定,因此相对于本地ResourceLoader的上下文应用)

image-20230116175205689

WritableResource

支持写资源的接口,提供了输出流的访问器;它代表可写的资源

image-20230116175226245

Spring中资源加载方式

  • ClassLoader

ClassPathResource [classpath:/]
  如果是classpath开头的资源路径,Spring解析后会自动到类路径下找;

  • File

FileSystemResource [file:/]
  如果是file开头的资源路径,则会去文件系统中找;

  • URL

UrlResource [xxx:/]
  如果是 URL 支持的协议开头,则底层会使用对应的协议,去尝试获取相应的资源文件;

FileSystemResource

java.io.File的一个包装,区别在于它是订制于Spring的Resource体系下的.

image-20230116173943442

ClassPathResource

ClassPathResource表示从类路径获取的资源,通常使用线程上下文的ClassLoader进行资源加载.
我们的Web项目通常编译后,会将class文件存储在WEB-INF/classes下,Spring就可以通过ClassPathResource来访问这些文件.

image-20230116174333229

UrlResource

UrlResource 封装了 java.net.URL,可用于访问通常可通过 URL 访问的任何对象,如文件、HTTP 目标、FTP 目标等。所有 URL 都有一个标准化的字符串表示,这样就可以使用适当的标准化前缀来表示不同的URL类型。通常有:

  • file:用于访问文件系统路径
  • http:用于通过http协议访问资源
  • ftp:用于通过ftp访问资源

image-20230116174351275

其他Resource

ServletContextResource

这是ServletContext资源的Resource实现,它解析相关Web应用程序根目录中的相对路径。
它始终支持流(stream)访问和URL访问,但只有在扩展Web应用程序存档且资源实际位于文件系统上时才允许java.io.File访问。无论它是在文件系统上扩展还是直接从JAR或其他地方(如数据库)访问,实际上都依赖于Servlet容器。

image-20230116174832962

InputStreamResource

返回一个仅一次使用的流,如果你要多次使用流,不要选择它。InputStreamResource 是给定 InputStream 的资源实现。只有在没有特定的资源实现可用时,才应该使用它。特别是,尽可能选择 ByteArrayResource 或任何基于文件的资源实现。

image-20230116174815047

ByteArrayResource

这是一个给定字节数组的资源实现。它为给定的字节数组创建一个 ByteArrayInputStream。它对于从任何给定的字节数组加载内容都很有用,而不必求助于一次性使用的 InputStreamResource。

image-20230116174754441

ResourceLoader

整体结构图

image-20230116173025540

ResourceLoader

解析

从名称来看,我们可以了解到这是一个资源加载器,也正如我们所想的,该接口是用来加载资源(例如类路径或者文件系统中的资源)的策略接口。这个接口里面只有两个接口,一个获取指定路径的资源,一个是获取资源加载器的类加载器,如图:

image-20230117094738467

当然,我们也可以看到里面有一个常量,这是我们加载资源是的前缀(classpath:)

单文件加载--------------------------------------------------------

image-20230117142033563

DefaultResourceLoader

作用

DefaultResourceLoader是spring提供的一个默认的资源加载器,DefaultResourceLoader实现了ResourceLoader接口,提供了基本的资源加载能力。实现了单个资源文件的加载。
DefaultResourceLoader包含了一个protocolResolvers的set集,可以通过添加ProtocolResolver来提供不同协议资源的读取能力,默认情况下protocolResolvers是空的,我们可以通过添加ProtocolResolver扩展DefaultResourceLoader的能力。

解析

image-20230117101324007

如上图,这是DefaultResourceLoader实现了ResourceLoader的getResource方法,这个方法将非URL资源路径视为类路径资源(支持包含包路径的完整类路径资源名称),除非在子类重写getResourceByPath方法。我们再看getResourceByPath方法的实现:

image-20230117102258737

image-20230117102315748

我们可以看到,这个方法的内容是使用内部类ClassPathContextResource的,而内部类又使用了ClassPathResource,最终将路径转换成了类路径。当然,我们可以发现这个方法是protected类型的,它本身是可以被子类重写的,我们再看下图:

image-20230117102916576

我们可以发现,AbstractApplicationContext是继承了DefaultResourceLoader的,所以是有可能有子类ApplicationContext重写此方法的,实际上,如果引入了spring-web模块中的依赖,这时getResourceByPath会被几个Web级的子类重写该方法,如下图,红框中都是重写的:

image-20230117103542500

举个例子:

image-20230117103614795

补充:ProtocolResolver

ProtocolResolver是一个函数式接口,实现该接口可以通过自定义不同的协议来读取解析资源路径中的资源。

使用示例:

在resources目录下创建一个resource目录,并在resource目录下创建一个demo.txt文件,demo.txt文件内容可以随意,当程序运行时会从该路径下加载,并通过缓冲流读取

 public class DemoProtocolResolver implements ProtocolResolver {

    public static final String DEMO_PATH_PREFIX = "demo:";

    @Override
    public Resource resolve(String location, ResourceLoader resourceLoader) {
        if (!location.startsWith(DEMO_PATH_PREFIX)) {
            return null;
        }

        String realpath = location.substring(DEMO_PATH_PREFIX.length());
        String classpathLocation = "classpath:resource/" + realpath;
        return resourceLoader.getResource(classpathLocation);
    }

    public static void main(String[] args) throws Exception {
        // 实例化DefaultResourceLoader DemoProtocolResolver
        DefaultResourceLoader resourceLoader = new DefaultResourceLoader();
        DemoProtocolResolver demoProtocolResolver = new DemoProtocolResolver();
        resourceLoader.addProtocolResolver(demoProtocolResolver);

        // ResourceLoader获取编写的demo.txt
        Resource resource = resourceLoader.getResource("demo:demo.txt");
        InputStream inputStream = resource.getInputStream();
        InputStreamReader reader = new InputStreamReader(inputStream, StandardCharsets.UTF_8);
        BufferedReader br = new BufferedReader(reader);
        String readLine;
        while ((readLine = br.readLine()) != null) {
            System.out.println(readLine);
        }
        br.close();
    }
}

ClassRelativeResourceLoader

解析

ClassRelativeResourceLoader扩展的功能是可以根据给定的class所在包或者所在包的子包下加载资源。

image-20230117135152161

FileSystemResourceLoader

JavaDoc

将普通路径解析为文件系统资源而不是类路径资源(后者是DefaultResourceLoader的默认策略)的ResourceLoader实现。

注意:普通路径将始终被解释为相对于当前虚拟机工作目录,即使它们以斜杠开头。(这与Servlet容器中的语义一致。)使用显式的“file:”前缀强制使用绝对文件路径。

解析

和ClassRelativeResourceLoader类似,重写了getResourceByPath方法:

image-20230117135618264

ServletContextResourceLoader

作用

可以从Servlet上下文的根目录加载资源。

解析

路径:/WEB-INF/test.xml

ServletContextResourceLoader是从上下文的根路径加载资源,上下文的根路径是webapp(在开发工具中比如eclipse中,指的就是webapp,当打成war包以后就是你项目打包的名字了...);

maven工程打包以后src/main/resources下的资源文件会被打到WEB-INF/classes下,所以需要在WEB-INF后添加classes

image-20230117140047502

多文件加载--------------------------------------------------------

image-20230117142011122

ResourcePatternResolver

解析

从下图我们就可以看出,ResourcePatternResolver支持Ant形式的带星号( * )的路径解析,从而支持多个资源文件的加载:

image-20230117105256924

PathMatchingResourcePatternResolver

我们在上面有说过Spring加载资源的三种方式,除了类路径、文件系统以及url这三种,我们还支持Ant风格路径模式的解析,PathMatchingResourcePatternResolver就是支持Ant风格路径模式解析的实现类。如图:

image-20230117141227094

image-20230117141347299

当然上面的是(classpath*:)这个多路径匹配模式,如果你使用的是(classpath:)的,那么你会使用DefaultResourceLoader或者你指定的资源加载器进行路径解析:

image-20230117141900322

ServletContextResourcePatternResolver

解析

ServletContextResourcePatternResolver是PathMatchingResourcePatternResolver的子类,相较于PathMatchingResourcePatternResolver,ServletContextResourcePatternResolver针对ServletContextResource做了针对性处理

image-20230117115742434

附录

Ant-style Patterns

Ant(路径匹配表达式)风格的通配符解析

PatternDescriptionExampleRemark
?匹配任何的单个字符example/?ork可以匹配:example/fork;example/work
*匹配0或者任意数量的字符file:C:/some/path/*.xml可以匹配C:/some/path下的所有xml文件
**匹配0个或者更多的目录classpath:com/mycompany/**/applicationContext.xml可以匹配mycompany和applicationContext.xml的任意目录,例如: classpath:com/mycompany/test/applicationContext.xml; classpath:com/mycompany/work/applicationContext.xml.

引用

https://www.cnblogs.com/coder-zyc/p/16464495.html

https://www.jianshu.com/p/646d801e055d

https://blog.csdn.net/seasonsbin/article/details/80914911
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值