深入Spring IOC源码之Resource(一)

2014-11-24 10:36:17 · 作者: · 浏览: 0

Java中,将不同来源的资源抽象成URL,通过注册不同的handler(URLStreamHandler)来处理不同来源的资源的读取逻辑,一般handler的类型使用不同前缀(协议,protocol)来识别,如“file:”、“http:”、“jar:”等,然而URL没有默认定义相对classpath或ServletContext等资源的handler,虽然可以注册自己的URLStreamHandler来解析特定的URL前缀(协议),比如“classpath:”,然而这需要了解URL的实现机制,而且URL也没有提供一些基本的方法,如检查当前资源是否存在、检查当前资源是否可读等方法。因而Spring对其内部使用到的资源实现了自己的抽象结构:Resource接口来封装底层资源:

public interface InputStreamSource {

InputStream getInputStream() throws IOException;

}

public interface Resource extends InputStreamSource {

boolean exists();

boolean isReadable();

boolean isOpen();

URL getURL() throws IOException;

URI getURI() throws IOException;

File getFile() throws IOException;

long lastModified() throws IOException;

Resource createRelative(String relativePath) throws IOException;

String getFilename();

String getDescription();

}

InputStreamSource封装任何能返回InputStream的类,比如File、classpath下的资源、Byte Array等。它只有一个方法定义:getInputStream(),该方法返回一个新的InputStream对象。

Resource接口抽象了所有Spring内部使用到的底层资源:File、URL、classpath等。首先,它定义了三个判断当前资源状态的方法:存在性(exists)、可读性(isReadable)、是否处于打开状态(isOpen)。在C语言中,当我们拿到一个文件句柄时,我们要调用open方法打开文件才可以真正读取该文件,但是在Java中并没有显示的定义open方法,一般当我们创建一个InputStream、Reader时,该资源(文件)就已经处于打开状态了,因而这里的isOpen方法并不是判断当前资源是否已经处于打开的可操作状态,这里是表示Resource接口所抽象的底层资源是否可以多次调用getInputStream()方法,如果该方法返回true,则不可以多次调用getInputStream()方法。在Spring 2.5.6的实现中,只有InputStreamResource类的isOpen()方法返回true,其余都返回false。

另外,Resource接口还提供了不同资源到URL、URI、File类型的转换,以及获取lastModified属性、文件名(不带路径信息的文件名,getFilename())的方法。为了便于操作,Resource还提供了基于当前资源创建一个相对资源的方法:createRelative();在错误处理中需要详细的打印出错的资源文件,因而Resource还提供了getDescription()方法用于在错误处理中的打印信息。

在Spring 2.5.6中,所有实现Resource的接口类继承关系图如下:


即对不同来源的资源文件都有相应的Resource实现:文件(FileSystemResource)、classpath资源(ClassPathResource)、URL资源(UrlResource)、InputStream资源(InputStreamResource)、Byte数组(ByteArrayResource)等。

AbstractResource类

AbstractResource是对Resource的基本实现,所有Resource实现类都继承了该类,所有继承该类的Resource一般只需要实现以下方法即可:

public File getFile() throws IOException

public URL getURL() throws IOException

public String getDescription()

public InputStream getInputStream() throws IOException

该类默认实现中,将toString、equals、hashCode都代理给Description属性;isReadable总是返回true,而isOpen总是返回false;exists方法实现中,先调用getFile返回的File对象的exists方法,如果失败,查看是否可以获得InputStream,如果可以,返回true,否则,返回false;getURL和getFile、createRelative方法抛出FileNotFoundException,而getURI则代理给getURL方法。

ByteArrayResource类

ByteArrayResource是一个简单的Resource实现,它是对二进制数组的封装,每次调用getInputStream时都会以这个二进制数组作为源创建一个ByteArrayInputStream。它的exists方法总是返回true,而且重写了equals、hashCode的方法,以判断二进制数组的内容;它的description属性可以是用户自定义,也可以使用默认值:resource loaded from byte array

public final byte[] getByteArray() {

return this.byteArray;

}

public boolean exists() {

return true;

}

public InputStream getInputStream() throws IOException {

return new ByteArrayInputStream(this.byteArray);

}

FileSystemResource类

FileSystemResource是对File的封装,在构建FileSystemResource时可以传入File对象或路径字符串(这里的路径可以是相对路径,相对路径是相对于System.getProperty(“user.dir”)的值所在的路径,也可以是绝对路径,也可以是“file:”开头的路径值),在内部会创建相应的File对象,并且计算其path值,这里的path是计算完“.”和“..”影响的值(规格化)。

在getInputStream方法中,使用该File对象创建FileInputStream;而path值作为desc