Spring 中的资源加载
在Spring框架中,Resource接口用于简化和统一对各种底层资源(如xxx.xml、application.yml、application.properties
等文件、类路径资源、URL等)的访问。它提供了一个通用的抽象层,使开发者无需关注不同资源类型的具体访问方式。在Java开发中,访问资源是一个常见需求,例如读取配置文件、加载图片、音频等。Java标准库为不同类型的资源提供了各自的访问方式。例如,文件系统资源通常使用java.io.File类,类路径资源可能使用ClassLoader
的getResource
或getResourceAsStream
方法,而网络资源则可以通过java.net.URL类进行访问。这些不同的机制意味着开发者需要熟悉多种方式来访问资源,这可能导致代码复杂性增加、重复代码出现以及更高的错误风险。
为了解决这些问题并提供一个更统一的资源访问方式,Spring框架引入了Resource接口。Resource接口为所有资源类型提供了一个通用的抽象,使得无论资源来自文件系统、类路径还是网络,开发者都可以通过一致的方式进行访问。这不仅简化了资源访问的代码,还提高了代码的可维护性和可读性。此外,Spring还提供了多个Resource接口的实现类,例如FileSystemResource、ClassPathResource、UrlResource
等,这些类专门用于处理特定类型的资源。通过使用这些实现类,开发者可以轻松地从不同来源获取资源,而不必担心底层的实现细节。总之,Resource接口及其实现类为资源访问提供了一种高度抽象和简化的解决方案,是Spring框架中一个非常有用的功能。
本文将从Resource
接口开始介绍,最后将介绍常用的Resources接口的实现类ResourceLoader
、ResourcePatternResolver
、DocumentLoader
等。
Resource
接口
Spring中将所有的资源抽象成了Resource对象,对于不同的资源类型有着不同的实现类,它为访问底层资源提供了一个统一的抽象,从而使得代码可以独立于实际资源的类型。首先我们打开Resource源代码如下所示:
/**
* 用于描述资源的接口,该接口抽象了底层资源的实际类型,如文件或类路径资源。
*
* <p>对于每个资源,如果它在物理形式上存在,都可以打开一个输入流,但只有某些资源才能返回 URL 或文件句柄。具体行为取决于其实现。
*/
public interface Resource extends InputStreamSource {
/**
* 判断此资源是否在物理形式上真正存在。
*/
boolean exists();
/**
* 指示是否可以通过 {@link #getInputStream()} 读取此资源的非空内容。
* 实际的内容读取可能仍然失败。
*/
default boolean isReadable() {
return exists();
}
/**
* 指示此资源是否代表一个打开的流的句柄。
* 如果为 true,则输入流不能被多次读取,并且在读取后必须被关闭,以避免资源泄露。
*/
default boolean isOpen() {
return false;
}
/**
* 判断此资源是否代表文件系统中的文件。
*/
default boolean isFile() {
return false;
}
/**
* 返回此资源的 URL 句柄。
*/
URL getURL() throws IOException;
/**
* 返回此资源的 URI 句柄。
*/
URI getURI() throws IOException;
/**
* 返回此资源的文件句柄。
*/
File getFile() throws IOException;
/**
* 返回一个 {@link ReadableByteChannel}。
*/
default ReadableByteChannel readableChannel() throws IOException {
return Channels.newChannel(getInputStream());
}
/**
* 确定此资源的内容长度。
*/
long contentLength() throws IOException;
/**
* 确定此资源的最后修改时间戳。
*/
long lastModified() throws IOException;
/**
* 创建相对于此资源的资源。
*/
Resource createRelative(String relativePath) throws IOException;
/**
* 返回此资源的文件名。
*/
@Nullable
String getFilename();
/**
* 返回此资源的描述,用于在处理资源时的错误输出。
*/
String getDescription();
}
可以看见Resource
接口是InputStreamSource
的子类,我们可以看一下InputStreamSource
的源码如下:
/**
* 表示可以提供输入流的资源或对象的接口。
*/
public interface InputStreamSource {
/**
* 返回基础资源内容的 InputStream。
* 期望每次调用都会创建一个新的流。
* @return 基础资源的输入流(不能为 null)
* @throws java.io.FileNotFoundException 如果基础资源不存在
* @throws IOException 如果无法打开内容流
*/
InputStream getInputStream() throws IOException;
}