1. Spring Framework中的资源Resource
1.1 Resource的源码
在org.springframework.core.io包中的Resource接口,作为所有资源的统一抽象,它继承 org.springframework.core.io.InputStreamSource接口,在Resource 定义了一些通用的方法,由子类 AbstractResource 提供统一的默认实现。Resource 的代码如下:
public interface Resource extends InputStreamSource {
/**
* 资源是否存在
*/
boolean exists();
/**
* 资源是否可读
*/
default boolean isReadable() {
return exists();
}
/**
* 指示此资源是否表示具有开放流的句柄。如果为true,则不能多次读取InputStream,
* 必须读取并关闭InputStream以避免资源泄漏。对于典型的资源描述符,将为false。
*/
default boolean isOpen() {
return false;
}
/**
* 是否 File
*/
default boolean isFile() {
return false;
}
/**
* 返回资源的 URL
*/
URL getURL() throws IOException;
/**
* 返回资源的 URI
*/
URI getURI() throws IOException;
/**
* 返回资源的 File
*/
File getFile() throws IOException;
default ReadableByteChannel readableChannel() throws IOException {
return Channels.newChannel(getInputStream());
}
/**
* 资源内容的长度
*/
long contentLength() throws IOException;
/**
* 资源的最后修改时间
*/
long lastModified() throws IOException;
/**
* 根据相对路径创建资源
*/
Resource createRelative(String relativePath) throws IOException;
/**
* 确定此资源的文件名,即通常路径的最后一部分:例如“myfile.txt”。如果此类型的资源没有文件名,则返回null
*/
@Nullable
String getFilename();
/**
* 资源的描述
*/
String getDescription();
1.2 Resource相关的类图
从上面类图可以看到,Resource 根据资源的不同类型提供不同的具体实现,如下:
- FileSystemResource :对 java.io.File 类型资源的封装,只要是跟 File 打交道的,基本上与 FileSystemResource 也可以打交道;
- ByteArrayResource :对字节数组提供的数据的封装。如果通过 InputStream 形式访问该类型的资源,该实现会根据字节数组的数据构造一个相应的 ByteArrayInputStream;
- UrlResource :对 java.net.URL类型资源的封装。内部委派 URL 进行具体的资源操作;
- ClassPathResource :class path 类型资源的实现。使用给定的 ClassLoader 或者给定的 Class 来加载资源。
- InputStreamResource : 将给定的 InputStream 作为一种资源的 Resource 的实现类。
1.3 AbstractResource的源码
AbstractResource是个抽象类,为 Resource 接口的默认抽象实现。它实现了 Resource 接口的大部分的公共实现,是Resource接口最重要的实现,源码如下:
public abstract class AbstractResource implements Resource {
/**
* 此实现检查文件是否可以打开,若判断过程产生错误或者异常,就关闭对应的流
*/
@Override
public boolean exists() {
// 基于 File 文件系统进行判断
if (isFile()) {
try {
return getFile().exists();
}
catch (IOException ex) {
Log logger = LogFactory.getLog(getClass());
if (logger.isDebugEnabled()) {
logger.debug("Could not retrieve File for existence check of " + getDescription(), ex);
}
}
}
//若判断过程产生错误或者异常,就关闭对应的流
try {
getInputStream().close();
return true;
}
catch (Throwable ex) {
Log logger = LogFactory.getLog(getClass());
if (logger.isDebugEnabled(