Spring Resource资源文件体系

孤者浪人 提交于 2020-07-28 08:00:32

1. Resource接口

Spring对于资源加载有着一套自己的框架——Resource,Resource继承自InputStream。 下面的是Resource的源码:

public interface Resource extends InputStreamSource {
    boolean exists();//判断资源是否存在
    default boolean isReadable() {
        return true;
    }
    //判断资源是否打开
    default boolean isOpen() {
        return false;
    }
    //判断资源是否是一个文件
    default boolean isFile() {
        return false;
    }
    //获取资源文件的URL
    URL getURL() throws IOException;
    //获取资源文件的URI
    URI getURI() throws IOException;
    //获取资源文件的File对象
    File getFile() throws IOException;
    ///这个方法接口中有默认实现,返回的是ReadableByteChannel,这个类属于Java的NIO中的管道。
    default ReadableByteChannel readableChannel() throws IOException {
        return Channels.newChannel(getInputStream());
    }
    //获取内容的长度,这个方法返回一个long,因为文件内容可能很长。
    long contentLength() throws IOException;
    //这个方法返回的是最后修改时间,虽然也返回的是long,但是这个数字是一个时间戳。
    long lastModified() throws IOException;
    //这个方法根据relativePath相对路径返回一个相对与该Resource的Resource。
    Resource createRelative(String relativePath) throws IOException;
    @Nullable
    //获取文件的名字。
    String getFilename();
    //获取一个对该资源的一个描述。
    String getDescription();

}

2. Resource实现类

你可以理解为,Resource就是一个增强版的InputStreamSource,Resource 接口是Spring资源访问策略的抽象,它本身并不提供任何资源访问实现,具体的资源访问由该接口的实现类完成——每个实现类代表一种资源访问策略(策略模式)。

  • UrlResource:
    • UrlResource封装了java.net.URL,可用于访问通常可通过url访问的任何对象,如文件、HTTP目标、FTP目标和其他对象。所有URL可以使用一个标准化前缀来表示一个URL类型。例如: file:用于访问文件系统路径。 http:用于通过HTTP协议访问资源。 ftp:用于通过FTP访问资源。
  • ClassPathResource:
    • 表示从类路径加载资源。如果资源路径带上前缀ClassPath:,那么会隐式的解析为ClassPathResource。注意,如果类资源文件是在文件系统中,则该资源实现会被解析为java.io.File, 如果是在Jar包中,则会使用java.net.URL来解析。
  • FileSystemResource:
    • 他是java.io.File和java.nio.file.Path的Resource实现,支持解析为File或者URL。如D:/aaa/vvv.java
  • ServletContextResource:
    • 这是ServletContext的Resource实现,用于解释相关Web应用程序根目录中的相对路径。访问Web容器上下文中的资源而设计的类,负责对于Web应用根目录的路径加载资源。它支持以流和URL的方式访问,在WAR解包的情况下,也可以通过File方式访问。该类还可以直接从JAR包中访问资源。
  • InputStreamResource:
    • InputStreamResource 是InputStream 的Resource实现。只有在其他Resource实现不可用的时候才考虑使用它。和其他的Resource实现相反,它是一个already-opened resource的描述器,所以isOpen()会返回true。 如果你想保存资源描述器或者多次读取一个stream, 那么不要使用它。
  • ByteArrayResource:
    • 是byte array的Resource实现, 它创建了ByteArrayInputStream。它对于从任何给定的字节数组加载内容都很有用,而不必求助于单次使用的InputStreamResource。
  • PathResource:
    • Spring4.0提供的读取资源文件的新类。Path封装了java.net.URL、java.nio.Path、文件系统资源,它使用户能够访问任何可以通过URL、Path、系统文件路径表示的资源,如文件系统的资源,HTTP资源、FTP资源等。

3. 使用示例

使用示例如下

    @Test
    public void testResource() throws IOException {
        String filePath = "E:\\源码\\Spring源码阅读\\testSpring\\src\\test\\resources\\spring.txt";

        // 1. 使用系统的文件路径方式加载文件
        WritableResource resource1 = new PathResource(filePath);

        // 2. 使用类路径方式加载文件
        Resource resource2 = new ClassPathResource("spring.txt");

        // 3. 使用WritableResource接口写资源文件
        OutputStream os = resource1.getOutputStream();
        os.write("Spring是一套非常优秀的框架".getBytes());

        // 4. 使用Resource接口读文件
        InputStream in1 = resource1.getInputStream();
        InputStream in2 = resource1.getInputStream();
        BufferedInputStream bis = new BufferedInputStream(in1);
        byte[] bytes = new byte[1024];
        bis.read(bytes);
        System.out.println(new String(bytes));
        System.out.println("resource1: " + resource1.getFilename());
        System.out.println("resource2: " + resource2.getFilename());
    }

4. 资源路径通配符。

Resource解析各种资源路径,依靠资源路径通配符可以带来很多方便。

4.1 Ant-style Patterns

定义资源路径可以是用Ant风格的通配符,下面是 Ant-style patterns 的路径例子:

/WEB-INF/*-context.xml
com/mycompany/**/applicationContext.xml
file:C:/some/path/*-cont?xt.xml
classpath:com/mycompany/**/applicationContext.xml

Ant风格的资源地址支持三种通配符:

  • ?:匹配文件名中的一个字符
  • *:匹配文件名中的多个字符
  • **:匹配多层路径。

4.2 classpath*:前缀

构造基于XML的ApplicationContext,路径地址可以使用classpath*: 前缀,如下:

ApplicationContext ctx =
    new ClassPathXmlApplicationContext("classpath*:conf/appContext.xml");

或者

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath*:applicationContext.xmlclasspath*:applicationContext-shiro.xml
        </param-value>
</context-param>

classpath* 和 classpath 的区别是:classpath* 会去查找所有匹配的classpath, 而classpath 只会找到第一个匹配的资源。

5. ResourceLoader

不过有个问题随之而来,那就是Resource的选择,这么多的Resource如何知道选择使用哪一个?Spring提供了一个强大的资源加载机制,他可以通过前缀标识加载资源,如:classpath:, file:,ftp:等,同时还支持使用Ant风格的通配符。

ResourceLoader用来返回Resource实例,下面是其定义:

public interface ResourceLoader {
    Resource getResource(String location);
}
前缀 例子 说明
classpath: classpath:com/myapp/config.xml 使用ClassPathResource从classpath中加载。
file: file:/data/config.xml 作为 URL 加载。使用UrlResource从文件系统目录中装载资源
http: http://myserver/logo.png 作为 URL 加载。使用UrlResource从Web服务器中装载资源
ftp: ftp://www.mcwebsite.top/bean.xml 作为 URL 加载。使用UrlResource从ftp服务器中装载资源
(none) /data/config.xml 根据ApplicationContext的具体实现选择对应类型的Resource

上表中最后一种情况,需要说明下:

所有的ApplicationContext都实现了ResourceLoader类。因此所有的ApplicationContext都可以用来获取Resource。

当在特定的应用程序上下文上调用getResource(),并且指定的位置路径没有特定的前缀时,将返回适合该特定应用程序上下文的资源类型。

例如,假设对ClassPathXmlApplicationContext实例执行了以下代码片段:

Resource template = ctx.getResource("some/resource/path/myTemplate.txt");

在ClassPathXmlApplicationContext中,这个方法返回ClassPathResource。

以此类推,在FileSystemXmlApplicationContext中,方法返回FileSystemResource。在WebApplicationContext, 方法返回ServletContextResource。

当然,就像我们表中说的,我们可以强制使用ClassPathResource,而不管ApplicationContext到底是什么。这样做的话,我们需要添加classpath:前缀。如下:

Resource template = ctx.getResource("classpath:some/resource/path/myTemplate.txt");

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath*:applicationContext.xmlclasspath*:applicationContext-shiro.xml
        </param-value>
</context-param>

同样的,你可以强制使用UrlResource通过添加标准的java.net.URL前缀(context-param配置的话同理):

Resource template = ctx.getResource("file:///some/resource/path/myTemplate.txt");

Resource template = ctx.getResource("https://myhost.com/resource/path/myTemplate.txt");
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!