2.1 引言
本节主要介绍Spring如何处理资源,以及如何在Spring使用资源。包含
- Introduction
- The Resource Interface
- Built-in Resource Implementations
- The
ResourceLoader
- The
ResourceLoaderAware
interface - Resources as Dependencies
- Application Contexts and Resource Paths
由于java.net.URL
类和各种 URL
标准实现并不满足对低级资源的所有访问,所以需要更高一级的抽象。
2.2 资源接口
Spring 的 Resource
接口旨在成为一个更有能力的接口,用于抽象对底层资源的访问。
public interface Resource extends InputStreamSource {
// 返回true/false。表示此资源是否物理存在
boolean exists();
// 返回true/false。表示此资源是否代表具有打开流的句柄。为true表示不能多次读取InputStream。
// 必须读一次关一次,从而避免资源泄漏。通用的资源通常返回false,InputStreamResource除外。
boolean isOpen();
URL getURL() throws IOException;
File getFile() throws IOException;
Resource createRelative(String relativePath) throws IOException;
String getFilename();
String getDescription();
}
扩展了 InputStreamSource
接口
public interface InputStreamSource {
// 定位并撕开资源,返回一个InputStream以便从该资源读取。调用者有必要关闭流
InputStream getInputStream() throws IOException;
}
2.3 内置资源的实现
包含以下资源的实现:
- UrlResource
- ClassPathResource
- FileSystemResource
- ServletContextResource
- InputStreamResource
- ByteArrayResource
2.3.1 UrlResource
UrlResource
包装了一个java.net.URL
,可以用来访问通常可以通过 URL 访问的任何对象,比如文件、 HTTP 目标、 FTP 目标等。所有 URL 都具有标准化的 String 表示形式,这样就可以使用适当的标准化前缀来表示一种 URL 类型与另一种 URL 类型。这包括文件: 用于访问文件系统路径,HTTP: 用于通过 HTTP 协议访问资源,FTP: 用于通过 FTP 访问资源,以及其他。
一个UrlResource
是由 Java 代码通过显式地使用UrlResource
构造函数创建的,但是通常在调用一个 API 方法时隐式地创建,该方法采用一个 String 参数来表示一个路径。对于后一种情况,javabeanPropertyEditor
最终决定创建哪种类型的Resource
。2.3.2 ClassPathResource
此类表示应该从类路径
获取的资源。
It uses either the thread context class loader, a given class loader, or a given class for loading resources.2.3.3 FileSystemResource
这是java.io.File
和java.nio.file.Path
句柄的Resource实现。 它支持作为文件和URL的解析。2.3.4 ServletContextResource
这是ServletContext
资源的一个资源实现,它解释了相关 web 应用程序根目录中的相对路径。2.3.5 InputStreamResource
InputStreamResource
是给定InputStream
的 Resource 实现。只有在没有特定的 Resource 实现可用的情况下才应该使用它。特别是,如果可能的话,最好使用ByteArrayResource
或任何基于文件的 Resource 实现。2.3.6 ByteArrayResource
这是一个给定字节数组的资源实现,它为给定的字节数组创建一个ByteArrayInputStream
。
对于从任何给定的字节数组加载内容,而不必求助于一次性使用的InputStreamResource
,它非常有用。2.3.7 ResourceLoader
ResourceLoader 接口意味着由可以返回(即加载) Resource 实例的对象实现。下面的清单显示了 ResourceLoader 接口定义:
所有应用程序上下文都实现了public interface ResourceLoader { Resource getResource(String location); }
ResourceLoader
接口。因此,所有应用程序上下文都可用于获取 Resource 实例。
Prefix | Example | Explanation |
---|---|---|
classpath: | classpath:com/myapp/config.xml |
Loaded from the classpath. |
file: | [file:///data/config.xml]() |
Loaded as a URL from the filesystem. See also FileSystemResource Caveats. |
http: | [https://myserver/logo.png](https://myserver/logo.png) |
Loaded as a URL . |
(none) | /data/config.xml |
Depends on the underlying ApplicationContext . |
2.5 ResourceLoaderAware接口
ResourceLoaderAware
接口是一个特殊的回调接口,用于标识希望通过 ResourceLoader 引用提供的组件。
public interface ResourceLoaderAware {
void setResourceLoader(ResourceLoader resourceLoader);
}
2.6 Resources作为依赖
如果Bean本身将通过某种动态过程来确定并提供资源路径,那么对于Bean来说,使用ResourceLoader
接口加载资源可能是有意义的。 例如,考虑加载某种模板,其中所需的特定资源取决于用户的角色。 如果资源是静态的,则有必要完全消除对ResourceLoader接口的使用,让Bean公开所需的Resource属性,并期望将其注入其中。
然后注入这些属性很简单,因为所有应用程序上下文都注册并使用一个特殊的 JavaBeans PropertyEditor
,它可以将 String 路径转换为 Resource 对象。因此,如果 myBean 有一个类型为 Resource 的模板属性,那么可以为该资源配置一个简单的字符串,如下面的示例所示:
<bean id="myBean" class="...">
<property name="template" value="some/resource/path/myTemplate.txt"/>
</bean>
2.7 应用程序上下文和资源路径
2.7.1 构造应用程序上下文
应用程序上下文构造函数(针对特定的应用程序上下文类型)通常将字符串或字符串数组作为资源的位置路径,例如构成上下文定义的 XML 文件。
2.7.2. 应用上下文构造函数资源路径中的通配符
应用程序上下文构造函数值中的资源路径可以是简单路径(如先前所示),每个路径都具有到目标Resource
的一对一映射,或者可以包含特殊的 classpath *:
前缀或内部 Ant
样式的正则表达式(通过使用Spring的PathMatcher
实用程序进行匹配)。 后者都是有效的通配符。
这种机制的一种用途是当您需要进行组件样式的应用程序组装时,所有组件都可以将上下文定义片段“发布”到一个众所周知的位置路径,并且当使用前缀为classpath*:
的相同路径创建最终应用程序上下文时,将自动拾取所有组件片段。注意,这种通配特定于应用程序上下文构造函数中资源路径的使用(或者当您直接使用 PathMatcher 实用程序类层次结构时) ,并在构造时解析。它与资源类型本身没有任何关系。不能使用类路径 * : 前缀构造实际的资源,因为资源一次只能指向一个资源。
Ant-style Patterns
/WEB-INF/*-context.xml
com/mycompany/**/applicationContext.xml
file:C:/some/path/*-context.xml
classpath:com/mycompany/**/applicationContext.xml
当路径位置包含 ant 样式的模式时,解析程序遵循一个更复杂的过程来尝试解析通配符。它为直到最后一个非通配符段的路径生成一个 Resource,并从中获得一个 URL。文件从中获取,并通过遍历文件系统来解析通配符。
classpath*:
ApplicationContext ctx =
new ClassPathXmlApplicationContext("classpath*:conf/appContext.xml");
这个特殊的前缀指定必须获得所有与给定名称匹配的类路径资源(在内部,这实际上是通过调用 ClassLoader.getResources (…)) ,然后合并以形成最终的应用程序上下文定义。
Spring检索路径的能力来自JDK的 ClassLoader.getResources()
方法。
Such a resource may be in only one location, but when a path such as the preceding example is used to try to resolve it, the resolver works off the (first) URL returned by getResource("com/mycompany");
. If this base package node exists in multiple classloader locations, the actual end resource may not be there. Therefore, in such a case you should prefer using classpath*:
with the same Ant-style pattern, which searches all class path locations that contain the root package.