Spring的Resource接口位于包org.springframework.core.io中;
Spring定义Resource接口是为了提供更强的访问底层资源能力的抽象;
对spring来说Resource接口代表着物理存在的任何资源。
1.先看一下resource接口及其实现的类层次关系图: 对应的UML类图为:
其中,最常用的有四个:
ClassPathResource:通过 ClassPathResource 以类路径的方式进行访问;
FileSystemResource:通过 FileSystemResource 以文件系统绝对路径的方式进行访问;
ServletContextResource:通过 ServletContextResource 以相对于Web应用根目录的方式进行访问;
UrlResource :通过java.net.URL来访问资源,当然它也支持File格式,如“file:”。
1、先看一下Resource接口的定义:
- public interface Resource extends InputStreamSource {
- boolean exists();
- boolean isReadable();
- boolean isOpen();
- URL getURL() throws IOException;
- URI getURI() throws IOException;
- File getFile() throws IOException;
- long contentLength() throws IOException;
- long lastModified() throws IOException;
- Resource createRelative(String relativePath) throws IOException;
- String getFilename();
- String getDescription();
- }
它是spring访问资源最基本的接口。实际访问的时候直接用Resource接口就可以,不必使用其子类。其实经常用到的(resource的真正目的)方法是public InputStream getInputStream()。
2、FileSystemResource
- public InputStream getInputStream() throws IOException {
- return new FileInputStream( this. file);
- }
这里的file是使用传入(构造函数中)的path生成的File,然后使用该File构造FileInputStream作为方法的输出。
这里的path一般要给出绝对路径,当然也可以是相对路径,如果是相对路径要注意其根目录。例如在eclipse中,它的根目录就是你工程目录作为你的根目录。
3、ClassPathResource
- public InputStream getInputStream() throws IOException {
- InputStream is;
- if ( this. clazz != null) {
- is = this. clazz.getResourceAsStream( this. path);
- }
- else {
- is = this. classLoader.getResourceAsStream( this. path);
- }
- if (is == null) {
- throw new FileNotFoundException(getDescription() + " cannot be opened because it does not exist");
- }
- return is;
- }
这里是通过Class或者ClassLoader的getResourceAsStream()方法来获得InputStream的。其path一般都是以“classpath:”开头,如果以“classpath*:”开头表示所有与给定名称匹配的classpath资源都应该被获取。
4、ServletContextResource
- public InputStream getInputStream() throws IOException {
- InputStream is = this.servletContext.getResourceAsStream(this.path);
- if (is == null) {
- throw new FileNotFoundException("Could not open " + getDescription());
- }
- return is;
- }
ServletContextResource通过ServletContext的getResourceAsStream()来取得InputStream,这里path必须以“/”开头,并且相对于当前上下文的根目录。如常用的path="/WEB-INF/web.xml"。
5、UrlResource
- public InputStream getInputStream() throws IOException {
- URLConnection con = this. url.openConnection();
- ResourceUtils. useCachesIfNecessary(con);
- try {
- return con.getInputStream();
- }
- catch (IOException ex) {
- // Close the HTTP connection (if applicable).
- if (con instanceof HttpURLConnection) {
- ((HttpURLConnection) con).disconnect();
- }
- throw ex;
- }
- }
UrlResource 封装了java.net.URL,它能够被用来访问任何通过URL可以获得的对象,例如:文件、HTTP对象、FTP对象等。
所有的URL都有个标准的 String表示,这些标准前缀可以标识不同的URL类型,包括file:访问文件系统路径,http: 通过HTTP协议访问的资源,ftp: 通过FTP访问的资源等等。
在Spring配置文件中,我们只需要给出字符串类型的path即可,Spring会通过ResourceEditor(java.beans.PropertyEditor的子类)和ResourceLoader把给定的path转换为相应的Resource。
转换规则如下:
2. 通过ResourceLoader获取资源
在Spring里面还定义有一个ResourceLoader接口,该接口中只定义了一个用于获取Resource的getResource(String location)方法。它的实现类有很多,这里我们先挑一个DefaultResourceLoader来讲。DefaultResourceLoader在获取Resource时采用的是这样的策略:首先判断指定的location是否含有“classpath:”前缀,如果有则把location去掉“classpath:”前缀返回对应的ClassPathResource;否则就把它当做一个URL来处理,封装成一个UrlResource进行返回;如果当成URL处理也失败的话就把location对应的资源当成是一个ClassPathResource进行返回。
Java代码- @Test
- public void testResourceLoader() {
- ResourceLoader loader = new DefaultResourceLoader();
- Resource resource = loader.getResource("http://www.google.com.hk");
- System.out.println(resource instanceof UrlResource); //true
- //注意这里前缀不能使用“classpath*:”,这样不能真正访问到对应的资源,exists()返回false
- resource = loader.getResource("classpath:test.txt");
- System.out.println(resource instanceof ClassPathResource); //true
- resource = loader.getResource("test.txt");
- System.out.println(resource instanceof ClassPathResource); //true
- }
ApplicationContext接口也继承了ResourceLoader接口,所以它的所有实现类都实现了ResourceLoader接口,都可以用来获取Resource。
对于ClassPathXmlApplicationContext而言,它在获取Resource时继承的是它的父类DefaultResourceLoader的策略。
FileSystemXmlApplicationContext也继承了DefaultResourceLoader,但是它重写了DefaultResourceLoader的getResourceByPath(String path)方法。所以它在获取资源文件时首先也是判断指定的location是否包含“classpath:”前缀,如果包含,则把location中“classpath:”前缀后的资源从类路径下获取出来,当做一个ClassPathResource;否则,继续尝试把location封装成一个URL,返回对应的UrlResource;如果还是失败,则把location指定位置的资源当做一个FileSystemResource进行返回。
3 在bean中获取Resource的方式
通过上面内容的介绍,我们知道,在bean中获取Resource主要有以下几种方式:
1.直接通过new各种类型的Resource来获取对应的Resource。
2.在bean里面获取到对应的ApplicationContext,再通过ApplicationContext的getResource(String path)方法获取对应的Resource。
3.直接创建DefaultResourceLoader的实例,再调用其getResource(String location)方法获取对应的Resource。
4.通过依赖注入的方式把Resource注入到bean中。示例如下:
类ClassA:
Java代码- public class ClassA {
- //持有一个Resource属性
- private Resource resource;
- public void printContent() {
- if (resource != null && resource.exists()) {
- if (resource.isReadable()) {
- InputStream is;
- try {
- is = resource.getInputStream();
- BufferedReader br = new BufferedReader(new InputStreamReader(is));
- String line;
- while ((line=br.readLine()) != null) {
- System.out.println(line);
- }
- if (is != null) {
- is.close();
- }
- if (br != null) {
- br.close();
- }
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
- }
- public void setResource(Resource resource) {
- this.resource = resource;
- }
- }
applicationContext.xml文件:
Xml代码- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
- xsi:schemaLocation="http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
- http://www.springframework.org/schema/context
- http://www.springframework.org/schema/context/spring-context-3.0.xsd">
- <bean id="classA" class="com.xxx.ClassA">
- <property name="resource">
- <value>classpath:applicationContext.xml</value>
- </property>
- </bean>
- </beans>
从上面可以看到我们有一个类ClassA,其持有一个Resource属性,在Spring bean配置文件中我们直接给ClassA注入了属性resource。其对应的测试代码如下:
Java代码- @RunWith(SpringJUnit4ClassRunner.class)
- @ContextConfiguration("classpath:applicationContext.xml")
- public class Test1 {
- @Autowired
- private ClassA classA;
- @Test
- public void test() {
- classA.printContent();
- }
- }