Spring Resource详解

1,582 阅读3分钟

以下分析基于Java 8,spring 5.2.7.RELEASE版本。

getInputStream

在 spring 框架中,Resource 是一个接口,位于 spring-core 的 io 包中。它实现了 spring 框架对外部资源的引用和操作。

下面是 Resource 接口和相关类的类图:

Resource 接口继承了 InputStreamSource 接口,而 InputStreamSource 接口只有一个方法:

InputStream getInputStream() throws IOException;

getInputStream 方法是 Resource的核心功能,用于获取资源的内容。通过观察这个方法的实现可以快速地了解 Resource 和快速鉴别资源类型。各个 Resource 实现类的 getInputStream 方法实现如下:

Resrouce 实现类 getInputStream 方法实现
ClassPathResource return classLoader.getResourceAsStream(resourcePath)
UrlResource return url.openConnection().getInputStream()
FileUrlResource 继承 UrlResource
ByteArrayResource return new ByteArrayInputStream(byteArray)
FileSystemResource return Files.newInputStream(filePath)
PathResource return Files.newInputStream(path)
VfsResource return (InputStream) invokeVfsMethod(VIRTUAL_FILE_METHOD_GET_INPUT_STREAM, vfsResource)
ServletContextResource return servletContext.getResourceAsStream(path)
DescriptiveResource 抛异常

从上面的表格中各 Resource 实现类的 getInputStream 方法的实现可以看出,各个实现类分别是哪一种资源的映射:

ClassPathResource ClassPathResource 是类文件资源的映射,它通过 ClassLoader 的getResourceAsStream 方法访问指定路径 path 的类文件资源。

UrlResource UrlResource 是Url类资源的映射。当你仅持有一个 Url 且不关心这个 Url 的类型,却又需要把它当做 Resource 使用时,可以使用 UrlResource 实现。

FileUrlResource FileUrlResource 继承自 UrlResource,和 UrlResource 的主要区别是它主要针对文件系统的 Url 资源。它实现了 WritableResource 接口,是一个可写的资源,如果它内部的 Url 资源指向的不是文件系统的文件,则使用 WritableResource 接口时会产生异常。

ByteArrayResource ByteArrayResource 类内部存有一个字节数组类型的成员变量,该变量存储的内容本身就是资源。

FileSystemResource PathResource FileSystemResource 和 PathResource 都是用于访问文件系统的指定路径下的文件资源。唯一的区别就是 FileSystemResource 构造函数支持传入 File 类型的参数用于指定资源路径,而 PathResource 的构造函数支持传入 Uri 类型的参数。他们都以访问文件流的方式访问相关资源的内容。

VfsResource VfsResource 用于访问 JBoss 框架的 VFS(虚拟文件系统) 资源,它通过反射的方式调用相关类的方法获取资源。相关内容可以参考 VfsUtils 类的实现。

DescriptiveResource DescriptiveResource 并不直接指向任何一个资源,它可以被当做一个占位符使用。所以调用 getInputStream 方法的时候会直接抛出异常。

ServletContextResource ServletContextResource 映射的是 web 应用服务器的文件资源,资源路径的根目录跟 web 应用的主目录对应。

createRelative

createRelative 方法是 Resource 接口的方法,它用于创建一个基于当前资源相对路径下的资源。例如当前文件资源的路径为 /data/resource/foo.res,createRelative 方法传入参数为 bar.res 时,该方法返回一个路径为 /data/resource/bar.res 的 Resource 对象。

猜测 createRelative 是方便用户创建某个路径下多个资源的 Resource 对象,省略了自己拼接资源访问路径的实现。

WritableResource

从类图可以看到,实现了 WritableResource 接口的类只有 FileUrlResource, FileSystemResource 和 PathResource,这三个类映射的资源都是文件系统的文件,所以可以实现资源的写入操作。