资源抽象接口(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"%>
<jsp:directive.page import="org.springframework.web.context.support.ServletContextResource"/>
<jsp:directive.page import="org.springframework.core.io.Resource"/>
<jsp:directive.page import="org.springframework.web.util.WebUtils"/>
<%
//①注意文件资源地址以相对于Web应用根路径的方式表示
Resource res3 = new ServletContextResource(application,"/WEB-INF/classes/conf/file1.txt");
out.print(res3.getFilename()+"<br/>");
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());
}
}
}
网友评论