资源抽象接口(Resource)和资源加载

资源抽象接口(Resource)

  JDK所提供的访问资源的类(如java.net.URL,File等)并不能很好地满足各种底层资源的访问需求,比如缺少从类路径或者Web容器的上下文中获取资源的操作类。有鉴于此,Spring设计了一个Resource接口,它为应用提供了更强的访问底层资源的能力。该接口拥有对应不同资源类型的实现类。先来了解一下Resource接口的主要方法:

  • boolean exists():资源是否存在;
  • boolean isOpen():资源是否打开;
  • URL getURL() throws IOException:如果底层资源可以表示成URL,该方法返回对应的URL对象;
  • File getFile() throws IOException:如果底层资源对应一个文件,该方法返回对应的File对象;
  • InputStream getInputStream() throws IOException:返回资源对应的输入流。

  Resource在Spring框架中起着不可或缺的作用,Spring框架使用Resource装载各种资源,这些资源包括配置文件资源、国际化属性文件资源等。下图是Resource的具体实现类:


  • ByteArrayResource:二进制数组表示的资源,二进制数组资源可以在内存中通过程序构造;
  • ClassPathResource:类路径下的资源,资源以相对于类路径的方式表示;
  • FileSystemResource:文件系统资源,资源以文件系统路径的方式表示,如D:/conf/bena.xml等;
  • InputStreamResource:对应一个InputStream的资源;
  • ServletContextResource:为访问web容器上下文中的资源而设计的类,负责以相对于web应用根目录的路径加载资源,它支持以流和URL的方式访问,在WAR解包的情况下,也可以通过File的方式访问,该类还可以直接从jar包中访问资源;
  • UrlResource:封装了java.net.URL,它使用户能够访问任何可以通过URL表示的资源,如文件系统的资源,HTTP资源,FTP资源等。
      有了这个抽象的资源类后,我们就可以将spring的配置信息放置在任何地方(如数据库,LDAP中),只要最终可以通过Resource接口返回配置信息就可以了。

假设有一个文件位于Web 应用的类路径下,用户可以通过以下方式对这个文件资源进行访问:

  • 通过 FileSystemResource 以文件系统绝对路径的方式进行访问;
  • 通过 ClassPathResource 以类路径的方式进行访问;
  • 通过 ServletContextResource 以相对于Web 应用根目录的方式进行访问。
      相比于通过JDK 的File 类访问文件资源的方式,Spring 的Resource 实现类无疑提供了更加灵活的操作方式,用户可以根据情况选择适合的Resource 实现类访问资源。下面,我们分别通过FileSystemResource 和ClassPathResource 访问同一个文件资源。
package com.yeren;

import java.io.IOException;
import java.io.InputStream;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
public class FileSourceExample {
    public static void main(String[] args) {
        try {
            String filePath = "D:/abc.txt";
            //①使用系统文件路径方式加载文件
            Resource res1 = new FileSystemResource(filePath);
            //②使用类路径方式加载文件
            Resource res2 = new ClassPathResource("go.txt");
            InputStream ins1 = res1.getInputStream();
            InputStream ins2 = res2.getInputStream();
            System.out.println("res1:" + res1.getFilename());
            System.out.println("res2:" + res2.getFilename());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

  在获取资源后,用户就可以通过Resource 接口定义的多个方法访问文件的数据和其他的信息:如可以通过getFileName()获取文件名,通过getFile()获取资源对应的File 对象,通过getInputStream()直接获取文件的输入流。此外,还可以通过createRelative(StringrelativePath)在资源相对地址上创建新的文件。

  在 Web 应用中,用户还可以通过ServletContextResource 以相对于Web 应用根目录的方式访问文件资源,如下所示:
代码清单 3-15 resource.jsp

<%@ page language="java" contentType="text/html; charset=utf-8"
pageEncoding="utf-8"%>



<%
//①注意文件资源地址以相对于Web应用根路径的方式表示
Resource res3 = new ServletContextResource(application,"/WEB-INF/classes/conf/file1.txt");
out.print(res3.getFilename()+"
"); out.print(WebUtils.getTempDir(application).getAbsolutePath()); %>

  对于位于远程服务器(Web 服务器或FTP 服务器)的文件资源,用户可以方便地通过UrlResource 进行访问。

  资源加载时默认采用系统编码读取资源内容,如果资源文件采用特殊的编码格式,那么可以通过EncodedResource 对资源进行编码,以保证资源内容操作的正确性:

package com.baobaotao.resource;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.EncodedResource;
import org.springframework.util.FileCopyUtils;
public class EncodedResourceExample {
    public static void main(String[] args) throws Throwable {
        Resource res = new ClassPathResource("conf/file1.txt");
        EncodedResource encRes = new EncodedResource(res,"UTF-8");
        String content = FileCopyUtils.copyToString(encRes.getReader());
        System.out.println(content);
    }
}

资源加载

  为了访问不同类型的资源,必须使用相应的Resource实现类。是否可以仅通过资源地址的特殊标识就可以加载相应的资源呢?Spring提供了一个强大的加载资源的机制,不但能通过”classpath:”、”file:”等资源地址前缀识别不同的资源类型,还支持Ant风格带通配符的资源地址。

资源地址表达式
  1. classpath:从类路径中加载资源,classpath:和classpath:/是等价的,都是相对于类的根路径。
  2. file:从文件系统目录中加载资源,可采用绝对或相对路径
  3. http://:从Web服务器中装载资源
  4. ftp://:从FTP服务器中装载资源
  5. 没有前缀:根据ApplicationContext具体实现类采用对应类型的Resource
  其中”classpath:”前缀。假设一个名为baobaotao的应用分为3个模块,每个模块都对应一个配置文件,分别是module1.xml,module2.xml,module3.xml,都放到com.baobaotao目录下。使用”classpath:com/baobaotao/module.xml”将可以加载这三个模块的配置文件,而使用”classpath:com/baobaotao/module.xml”时只会加载一个模块的配置文件。
  Ant风格资源地址支持3种匹配符:
   ?:匹配文件名中的一个字符;
   *:匹配文件名中任意个字符;
   **:匹配多层路径;

下面是几个Ant风格的资源路径的事例:

  • classpath:com/t?st.xml 匹配com类路径下com/test.xml,com/tast.xml
  • file:D:/conf/*.xml 匹配文件系统D:/conf目录下所有以xml为后缀的文件;
  • classpath:com/**/test.xml 匹配com类路径下(当前目录及其子目录)的test.xml文件;
  • classpath:org/springframework/*/.xml 匹配类路径 org/springframework 下所有以xml为后缀的文件;
  • classpath:org/**/servlet/bla.xml 匹配类路径org/springframework/servlet/bla.xml,也匹配org/springframework/testing/servlet/bla.xml,还匹配org/servlet/bla.xml。

资源加载器
spring定义了一套资源加载的接口,并提供了实现类:


spring资源加载器接口及实现类

  ResourceLoader接口仅有一个getResource(String location)的方法,可以根据一个资源地址加载文件资源,不过,资源地址仅支持带资源类型前缀的表达式,不支持Ant风格的资源路径表达式。ResourcePatternResolver扩展ResourcceLoader接口,定义了一个新的接口方法:getResources(String locationPattern),该方法支持带资源类型前缀及Ant风格的资源路径的表达式。PathMatchingResourcePatternResolver是sping提供了标准实现类如下:

package com.techman.resource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
 
public class PatternResolerTest {
    public static void main(String []args)throws Throwable{
        //实例化资源加载器接口
        ResourcePatternResolver rpr=new PathMatchingResourcePatternResolver();//是Spring提供的标准实现类
        //加载所有类包com.techman(及子孙包)下以xml为后缀的文件
        Resource resources[]=rpr.getResources("classpath*:com/techman/**/*.xml");
        for(Resource resource:resources){
            System.out.println(resource.getDescription()); 
        }
    }
}

你可能感兴趣的:(资源抽象接口(Resource)和资源加载)