Spring Resources
概述
在日常程序开发中,处理外部资源是很繁琐的事情,我们可能需要处理 URL 资源、File 资源、ClassPath相关资源等等。并且在 java 中 Java .net.URL 类和用于各种 URL 前缀的标准处理程序对于所有对底层资源的访问都不够充分。处理各种各样的资源需要使用到不同的接口,这就增加了系统的复杂性。
对此 Spring 提供了 Resource 接口来统一这些底层资源一致的访问。Resource 接口是一个更强大的接口,用于抽象对底层资源的访问。
public interface Resource extends InputStreamSource {
boolean exists();
boolean isOpen();
URL getURL() throws IOException;
File getFile() throws IOException;
Resource createRelative(String relativePath) throws IOException;
String getFilename();
String getDescription();
}
Resource 继承了 InputStreamSource 下面是 InputStreamSource 的内容
public interface InputStreamSource {
InputStream getInputStream() throws IOException;
}
方法解析:
- getInputStream():每次调用都会返回一个与资源对应的 InputStream 字节流,调用者有必要在使用后关闭该资源。
- exists():返回 true 表示当前资源存在。
- isOpen():返回 Resource 代表的资源是否已经被打开。如果返回 true,则只能读取一次不能多次读取 InputStream,然后关闭,以避免资源泄漏。对于所有常见的 Resource 实现一般返回 false。
- getURL():返回 Resource 代表资源对应的 java.util.URL 对象。
- getFile():返回 Resource 代表资源对应的 java.io.File 对象。
- createRelative(String relativePath):用于创建相对于当前 Resource 代表资源的资源,比如当前 Resource 代表文件资源 “d:/test/” 则 createRelative(“test.txt”) 将返回表文件资源 “d:/test/test.txt” Resource 资源。
- getFilename():返回 Resource 代表资源对应的文件路径。
- getDescription():返回 Resource 代表资源的描述符,通常就是资源的全路径(实际文件名或实际 URL 地址)。
Spring 框架自身就非常广泛使用 Resource,在我们的项目中也可以使用并且可以非常方便的获取到目标资源。
内置 Resource 接口实现
- UrlResource
- ClassPathResource
- FileSystemResource
- ServletContextResource
- InputStreamResource
- ByteArrayResource
UrlResource
UrlResource 封装了 java.net.URL,可用于访问通过 URL 访问的任何对象,比如文件、HTTP 资源、FTP 资源等等。所有 URL 都有一个标准化的字符串表示,因此可以使用适当的标准化前缀来表示不同 URL 类型的 URL。一般支持如下资源访问。
- file:用于访问文件系统路径
new UrlResource("file:d/xxx.txt");
- http:用于通过 http 协议访问资源
new UrlResource("http://地址");
- ftp: 用于通过 ftp 访问资源
new UrlResource("ftp://地址");
ClassPathResource
ClassPathResource 表示从类路径获取资源,它使用线程上下文类加载器、给定的类加载器来加载资源。classpath 资源存在于类路径中的文件系统中或 jar 包里。
ClassPathResource 常用构造器
public ClassPathResource(String path);
public ClassPathResource(String path, @Nullable ClassLoader classLoader);
public ClassPathResource(String path, @Nullable Class<?> clazz);
- public ClassPathResource(String path):使用默认的类加载器记载 path 类路径下的资源
- public ClassPathResource(String path, @Nullable ClassLoader classLoader):使用指定的类加载器加载 path 类路径下的资源
- public ClassPathResource(String path, @Nullable Class clazz):只用指定的类加载 path 类路径下的资源
FileSystemResource
FileSystemResource 是 Resource 实现支持 java.io 和 java.nio.file.Path 的处理。
ServletContextResource
ServletContextResource 是 web 应用资源,ServletContext 资源的实现。用于简化 servlet 容器的 ServletContext 接口的 getResource 操作和 getResourceAsStream 操作。
InputStreamResource
InputStreamResource 是基于 InputStream 的实现,参数是一个 InputStream 只有在没有特定场景下的 Resource 的时候才使用它。
public InputStreamResource(InputStream inputStream);
public InputStreamResource(InputStream inputStream, @Nullable String description);
ByteArrayResource
ByteArrayResource 是给定一个 byte[] 数组的实现创建 ByteArrayInputStream。
ResourceLoader
ResourceLoader 用于返回 Resource 的实例。
public interface ResourceLoader {
Resource getResource(String location);
}
Spring 的 ApplicationContext 都实现了 ResourceLoader
- ClassPathXmlApplicationContext
- FileSystemXmlApplicationContext
- WebApplicationContext
因此可以使用 ApplicationContext 来获取资源实例,当在某个 ApplicationContext 实现类中调用 getResource 而参数没有指定特定的资源前缀时,将返回适合 ApplicationContext 实现实例的资源类型,下面是 ClassPathXmlApplicationContext 的执行代码
Resource template = ctx.getResource("some/resource/path/myTemplate.txt");
对于 ClassPathXmlApplicationContext 以上代码返回一个 ClassPathResource。
如果对 FileSystemXmlApplicationContext 实例执行相同的方法,它将返回FileSystemResource。对于 WebApplicationContext,它将返回一个 ServletContextResource。
另外也可以指定资源前缀比如 classpath: 强制使用 ClassPathResource 无论 ApplicationContext 实现实例类型是什么。
Resource template = ctx.getResource("classpath:some/resource/path/myTemplate.txt");
也可以使用其他前缀
Resource template = ctx.getResource("file:///some/resource/path/myTemplate.txt");
Resource template = ctx.getResource("https://myhost.com/resource/path/myTemplate.txt");
getResource 字符串参数对象转换为资源对象的策略
资源前缀 | 示例 | 说明 |
---|---|---|
classpath: | classpath:com/myapp/config.xml | 从 classpath 类路径加载 |
file: | file:///data/config.xml | 从文件系统中作为 URL 加载 |
http: | https://myserver/logo.png | 作为 URL 加载 |
(none) | /data/config.xml | 根据 ApplicationContext 实现实例加载 |
ResourceLoaderAware
ResourceLoaderAware 接口是一个特殊的回调接口,通过对应的 ApplicationContext 注入。
public interface ResourceLoaderAware {
void setResourceLoader(ResourceLoader resourceLoader);
}
当一个类实现 ResourceLoaderAware 接口时,Spring IoC 容器在加载该 bean 的时候将该 bean 类型识别为 ResourceLoaderAware 然后调用对应的 setResourceLoader(ResourceLoader resourceLoader) 方法并将 ApplicationContext 的实例的 getResource 方法返回实例传递进去
ApplicationContext 构建
ApplicationContext 的构建通常将字符串或字符串数组作为资源的位置路径。当字符串参数路径没有前缀时,加载 bean 的 Resource 实例依赖于 ApplicationContext 的实例。例如,考虑下面的例子,它创建了一个 ClassPathXmlApplicationContext:
ApplicationContext ctx = new ClassPathXmlApplicationContext("conf/appContext.xml");
appContext.xml 文件里的 bean 都是从类路径加载的,因为使用了 Classpathresource。
ApplicationContext 构建的通配符
构建 ApplicationContext 的参数路径可以是精确的路径 classpath:conf/appContext.xml 每个路径都有到目标资源的一对一映射。或者也可以包含特殊的字符 classpath*: 这种机制的一个用途是,当您需要进行依赖式的应用程序组装时。并且当使用以classpath*: 作为前缀的相同路径创建最终的 ApplicationContext 时,所有依赖包 classpath 都会自动被获取。
classpath 和 classpath* 区别
- classpath:用于加载类路径(包括jar包)中的一个且仅一个资源;对于多个匹配的也只返回一个。
- classpath* :用于加载类路径(包括jar包)中的所有匹配的资源。
注意:用 classpath*: 需要遍历所有的 classpath,所以加载效率会比较差一些尽量少使用。