2. Resources
2.1. Introduction
- 标准Java.net.URL类与各种URL前缀的标准处理程序不足以满足所有对低级资源的访问。eg:获取没有标准化的URL,需要注册一个新的处理程序去处理专门的URL前缀(比如http:),比较复杂。
- 缺少一些理想的功能。eg:检查所指向资源的存在性的方法。
所以,为了可以访问所有的低级资源,Spring推出了Resource接口。
2.2 Resource 接口
Spring的Resource接口旨在成为一种功能更强大的接口,用于抽象化对低级资源的访问。以下清单显示了Resource接口定义:
public interface Resource extends InputStreamSource {
//资源是否实际以物理形式存在
boolean exists();
//返回一个布尔值,指示此资源是否具有打开流的句柄。如果是true,则不能多次读取InputStream,必须只读取一次,然后关闭,以避免资源泄漏。
boolean isOpen();
//
URL getURL() throws IOException;
File getFile() throws IOException;
Resource createRelative(String relativePath) throws IOException;
String getFilename();
//返回此资源的描述,用于处理该资源时的错误输出。这通常是完全限定的文件名或资源的实际URL。
String getDescription();
}
如Resource接口的定义所示,它扩展了InputStreamSource 接口。以下清单显示了InputStreamSource 接口的定义:
public interface InputStreamSource {
//定位并打开资源,返回一个InputStream以便从资源中读取数据。预期每次调用都返回一个新的InputStream。调用者的职责是关闭流。
InputStream getInputStream() throws IOException;
}
2.3 内置资源实现
-
UrlResource
-
ClassPathResource
-
FileSystemResource
-
ServletContextResource
-
InputStreamResource
-
ByteArrayResource
2.4 ResourceLoader(资源加载器)
该ResourceLoader接口旨在返回(即加载)Resource实例的对象实现。以下清单显示了ResourceLoader 接口定义:
public interface ResourceLoader {
Resource getResource(String location);
}
所有应用程序上下文均实现该ResourceLoader接口。因此,所有应用程序上下文都可用于获取Resource实例。
当特定的应用程序上下文调用getResource()时,并且指定的位置路径没有特定的前缀时,您将获得Resource适合该特定应用程序上下文的类型。例如,假设针对ClassPathXmlApplicationContext实例执行了以下代码片段:
Resource template = ctx.getResource("some/resource/path/myTemplate.txt");
上面针对ClassPathXmlApplicationContext,该代码返回ClassPathResource。
如果对FileSystemXmlApplicationContext实例执行相同的方法,则将返回 FileSystemResource。
对于WebApplicationContext,它将返回 ServletContextResource。
类似地,它将为每个上下文返回适当的对象。(前提是,位置路径没有特定的前缀)
下表总结了将String对象转换为Resource对象的策略:
Prefix | Example | Explanation |
---|---|---|
classpath: | classpath:com/myapp/config.xml | 从类路径下加载 |
file: | file:///data/config.xml | 从文件系统加载作为URL |
http: | https://myserver/logo.png | 从服务器加载作为URL |
(none) | /data/config.xml | 取决于构成ApplicationContext的基础 |
2.5 ResourceLoaderAware接口
ResourceLoaderAware接口是一个特殊的回调接口,用于标识希望提供ResourceLoader引用的组件。下面的列表显示了resourceloaderware接口的定义:
public interface ResourceLoaderAware {
void setResourceLoader(ResourceLoader resourceLoader);
}
2.6 Resources as Dependencies
<bean id="myBean" class="...">
<property name="template" value="some/resource/path/myTemplate.txt"/>
</bean>
没有指定前缀, 应用上下文本身将被使用作为ResourceLoader。ClassPathResource, FileSystemResource, or 或ServletContextResource。
如果需要强制使用特定的Resource类型,可以使用前缀。以下两个示例演示如何强制使用ClassPathResource(用于访问类路径下资源)和UrlResource(后者用于访问文件系统文件):
<property name="template" value="classpath:some/resource/path/myTemplate.txt">
<property name="template" value="file:///some/resource/path/myTemplate.txt"/>
2.7 Application Contexts and Resource Paths
2.7.1 构造Application Contexts
2.7.2 应用程序上下文构造函数资源路径中的通配符(*)
Ant-style Patterns
/WEB-INF/*-context.xml
com/mycompany/**/applicationContext.xml
file:C:/some/path/*-context.xml
classpath:com/mycompany/**/applicationContext.xml
classpath*:前缀
ApplicationContext ctx =
new ClassPathXmlApplicationContext("classpath*:conf/appContext.xml");
这里是引用
其它说明
classpath:com / mycompany / ** / service-context.xml
classpath:如果要搜索的根包在多个类路径位置可用,则不能保证带有资源的蚂蚁样式模式找到匹配的资源。考虑以下资源位置示例:
com / mycompany / package1 / service-context.xml
现在考虑某人可能用来尝试找到该文件的Ant样式的路径:
classpath:com / mycompany / ** / service-context.xml
这样的资源可能只在一个位置,但是当使用诸如前面示例的路径尝试解析它时,解析器将根据返回的(第一个)URL工作 getResource(“com/mycompany”);。如果此基本包节点存在于多个类加载器位置,则实际的最终资源可能不存在。因此,在这种情况下,您应该首选使用classpath*:相同的Ant样式模式,该模式将搜索包含根包的所有类路径位置。
2.7.3 FileSystemResource注意事项
相对路径是相对于当前工作目录的,而绝对路径是相对于文件系统的根。
以下是相对路径,是否以 / 开头是无所谓的,下面两种形式是等效的。
ApplicationContext ctx =
new FileSystemXmlApplicationContext("conf/context.xml");
ApplicationContext ctx =
new FileSystemXmlApplicationContext("/conf/context.xml");
实际上,如果需要真正的绝对文件系统路径,应该加上 file 前缀
ApplicationContext ctx =
new FileSystemXmlApplicationContext("file:///conf/context.xml");