Resources
-
ResourceLoaderAware
-
Built-in Resource Implementations
-
ClassPathXmlApplicationContext
-
Wildcards
-
FileSystemResource Caveats
-
InputStreamSource
-
WritableResource :description: 本文讨论了 Spring 的 Resource 抽象,它允许以统一的方式访问不同类型的资源。Resource 接口表示可用于加载、读取和写入资源的对象。Spring 提供了多种内置的 Resource 实现(例如 UrlResource、ClassPathResource 和 FileSystemResource),每种实现都针对特定类型的资源进行了优化。应用程序上下文充当 ResourceLoader,它允许以应用程序上下文类型特定的方式加载资源。ResourcePatternResolver 接口扩展了 ResourceLoader,允许使用模式(例如 Ant 路径模式)解析资源位置。开发人员还可以实现 ResourceLoaderAware 接口以直接加载资源或使用基于注释的自动装配来注入 Resource 对象。
本章介绍了 Spring 如何处理资源以及如何在 Spring 中使用资源。它包括以下主题:
This chapter covers how Spring handles resources and how you can work with resources in Spring. It includes the following topics:
Introduction
不幸的是,Java 的标准 java.net.URL
类和各种 URL 前缀的标准处理程序不足以完全用于访问低级资源。例如,没有用于访问需要从类路径或相对于 ServletContext
获取的资源的标准化 URL
实现方式。虽然可以注册专门的 URL
前缀的新处理程序(类似于 http:
等前缀的现有处理程序),但这通常非常复杂,并且 URL
接口仍然缺少一些理想的功能,例如检查所指向的资源是否存在的方法。
Java’s standard java.net.URL
class and standard handlers for various URL prefixes,
unfortunately, are not quite adequate enough for all access to low-level resources. For
example, there is no standardized URL
implementation that may be used to access a
resource that needs to be obtained from the classpath or relative to a
ServletContext
. While it is possible to register new handlers for specialized URL
prefixes (similar to existing handlers for prefixes such as http:
), this is generally
quite complicated, and the URL
interface still lacks some desirable functionality,
such as a method to check for the existence of the resource being pointed to.
The Resource
Interface
Spring 的 Resource
接口位于 org.springframework.core.io.
包中,旨在成为一个更强大的接口来抽象对低级资源的访问。以下列表提供了 Resource
接口的概述。请参阅 Resource
javadoc 以了解进一步详情。
Spring’s Resource
interface located in the org.springframework.core.io.
package is
meant to be a more capable interface for abstracting access to low-level resources. The
following listing provides an overview of the Resource
interface. See the
Resource
javadoc for further details.
public interface Resource extends InputStreamSource {
boolean exists();
boolean isReadable();
boolean isOpen();
boolean isFile();
URL getURL() throws IOException;
URI getURI() throws IOException;
File getFile() throws IOException;
ReadableByteChannel readableChannel() throws IOException;
long contentLength() throws IOException;
long lastModified() throws IOException;
Resource createRelative(String relativePath) throws IOException;
String getFilename();
String getDescription();
}
正如 Resource
接口的定义所示,它扩展了 InputStreamSource
接口。以下列表显示了 InputStreamSource
接口的定义:
As the definition of the Resource
interface shows, it extends the InputStreamSource
interface. The following listing shows the definition of the InputStreamSource
interface:
public interface InputStreamSource {
InputStream getInputStream() throws IOException;
}
Resource
接口中一些最重要的方法是:
Some of the most important methods from the Resource
interface are:
-
getInputStream()
: Locates and opens the resource, returning anInputStream
for reading from the resource. It is expected that each invocation returns a freshInputStream
. It is the responsibility of the caller to close the stream. -
exists()
: Returns aboolean
indicating whether this resource actually exists in physical form. -
isOpen()
: Returns aboolean
indicating whether this resource represents a handle with an open stream. Iftrue
, theInputStream
cannot be read multiple times and must be read once only and then closed to avoid resource leaks. Returnsfalse
for all usual resource implementations, with the exception ofInputStreamResource
. -
getDescription()
: Returns a description for this resource, to be used for error output when working with the resource. This is often the fully qualified file name or the actual URL of the resource.
其他方法允许你获取表示资源的实际 URL
或 File
对象(如果底层实现兼容并支持该功能)。
Other methods let you obtain an actual URL
or File
object representing the
resource (if the underlying implementation is compatible and supports that
functionality).
Resource
接口的一些实现也实现了扩展的 WritableResource
接口以获取支持对其写入的资源。
Some implementations of the Resource
interface also implement the extended
WritableResource
interface
for a resource that supports writing to it.
Spring 本身在需要资源时广泛使用 Resource
抽象,作为许多方法签名中的参数类型。某些 Spring API 中的其他方法(例如,到各种 ApplicationContext
实现的构造函数)使用一个 String
,它以未修饰或简单形式用于创建适合该上下文实现的 Resource
,或通过 String
路径上的专用前缀,允许调用者指定必须创建和使用的特定 Resource
实现。
Spring itself uses the Resource
abstraction extensively, as an argument type in
many method signatures when a resource is needed. Other methods in some Spring APIs
(such as the constructors to various ApplicationContext
implementations) take a
String
which in unadorned or simple form is used to create a Resource
appropriate to
that context implementation or, via special prefixes on the String
path, let the
caller specify that a specific Resource
implementation must be created and used.
虽然 Resource
接口在很多情况下与 Spring 及其本身一起使用,但它实际上非常方便,在你自己的代码中将其作为一般的实用程序类,用于访问资源,即使你的代码不知道或不关心 Spring 的任何其他部分。虽然这会将你的代码与 Spring 耦合,但实际上只将其与一小部分实用程序类耦合,这些类用作 URL
的更强大的替换,并且可以被视为你为此目的将要使用的任何其他库的等效项。
While the Resource
interface is used a lot with Spring and by Spring, it is actually
very convenient to use as a general utility class by itself in your own code, for access
to resources, even when your code does not know or care about any other parts of Spring.
While this couples your code to Spring, it really only couples it to this small set of
utility classes, which serves as a more capable replacement for URL
and can be
considered equivalent to any other library you would use for this purpose.
|
The |
Built-in Resource
Implementations
Spring 包括几个内置的 Resource
实现:
Spring includes several built-in Resource
implementations:
对于在 Spring 中可用的 Resource
实现的完整列表,请参阅 Resource
javadoc 的“所有已知实现类”部分。
For a complete list of Resource
implementations available in Spring, consult the
"All Known Implementing Classes" section of the
Resource
javadoc.
UrlResource
UrlResource
封装一个 java.net.URL
,可以用于访问任何通常可以使用 URL 访问的对象,例如文件、HTTPS 目标、FTP 目标等。所有 URL 都有标准的 String
表示形式,以便使用适当的标准化前缀来指示一种 URL 类型与另一种 URL 类型。这包括 file:
(用于访问文件系统路径)、https:
(用于通过 HTTPS 协议访问资源)、ftp:
(用于通过 FTP 访问资源)等。
UrlResource
wraps a java.net.URL
and can be used to access any object that is
normally accessible with a URL, such as files, an HTTPS target, an FTP target, and
others. All URLs have a standardized String
representation, such that appropriate
standardized prefixes are used to indicate one URL type from another. This includes
file:
for accessing filesystem paths, https:
for accessing resources through the
HTTPS protocol, ftp:
for accessing resources through FTP, and others.
UrlResource
是通过明确使用 UrlResource
构造函数由 Java 代码创建的,但在你调用获取一个表示路径的 String
参数的 API 方法时通常会隐式创建 UrlResource
。对于后一种情况,一个 JavaBeans PropertyEditor
最终决定创建哪种类型的 Resource
。如果路径字符串包含属性编辑器(即)公认的前缀(例如 classpath:
),它会为该前缀创建一个适合的专门 Resource
。但是,如果它不识别该前缀,它会假定该字符串是一个标准 URL 字符串,并创建一个 UrlResource
。
A UrlResource
is created by Java code by explicitly using the UrlResource
constructor
but is often created implicitly when you call an API method that takes a String
argument meant to represent a path. For the latter case, a JavaBeans PropertyEditor
ultimately decides which type of Resource
to create. If the path string contains a
well-known (to property editor, that is) prefix (such as classpath:
), it creates an
appropriate specialized Resource
for that prefix. However, if it does not recognize the
prefix, it assumes the string is a standard URL string and creates a UrlResource
.
ClassPathResource
此类表示应从类路径获取的资源。它使用线程上下文类加载器、给定的类加载器或给定的类加载资源。
This class represents a resource that should be obtained from the classpath. It uses either the thread context class loader, a given class loader, or a given class for loading resources.
此 Resource
实现支持将类路径资源解析为 java.io.File
,如果类路径资源驻留在文件系统中,但对于驻留在 JAR 中且尚未展开(通过 servlet 引擎或无论环境是什么)到文件系统的类路径资源不支持。为了解决这个问题,各种 Resource
实现始终支持作为 java.net.URL
进行解析。
This Resource
implementation supports resolution as a java.io.File
if the class path
resource resides in the file system but not for classpath resources that reside in a
jar and have not been expanded (by the servlet engine or whatever the environment is)
to the filesystem. To address this, the various Resource
implementations always support
resolution as a java.net.URL
.
ClassPathResource
是通过明确使用 ClassPathResource
构造函数由 Java 代码创建的,但在你调用获取一个表示路径的 String
参数的 API 方法时通常会隐式创建 ClassPathResource
。对于后一种情况,一个 JavaBeans PropertyEditor
识别字符串路径上的特殊前缀 classpath:
,并在该情况下创建一个 ClassPathResource
。
A ClassPathResource
is created by Java code by explicitly using the ClassPathResource
constructor but is often created implicitly when you call an API method that takes a
String
argument meant to represent a path. For the latter case, a JavaBeans
PropertyEditor
recognizes the special prefix, classpath:
, on the string path and
creates a ClassPathResource
in that case.
FileSystemResource
这是一个适用于 java.io.File
控制的 Resource
实现。它还支持 java.nio.file.Path
控制,使用 Spring 的标准基于字符串的路径转换,但通过 java.nio.file.Files
API 执行所有操作。相反,对于基于 java.nio.path.Path
的纯支持,使用 PathResource
。FileSystemResource
支持作为 File
和 URL
进行解析。
This is a Resource
implementation for java.io.File
handles. It also supports
java.nio.file.Path
handles, applying Spring’s standard String-based path
transformations but performing all operations via the java.nio.file.Files
API. For pure
java.nio.path.Path
based support use a PathResource
instead. FileSystemResource
supports resolution as a File
and as a URL
.
PathResource
这是一个适用于 java.nio.file.Path
控制的 Resource
实现,通过 Path
API 执行所有操作和转换。它支持作为 File
和 URL
进行解析,还实现了扩展的 WritableResource
接口。PathResource
实际上是一个基于 java.nio.path.Path
的 FileSystemResource
的纯替代品,具有不同的 createRelative
行为。
This is a Resource
implementation for java.nio.file.Path
handles, performing all
operations and transformations via the Path
API. It supports resolution as a File
and
as a URL
and also implements the extended WritableResource
interface. PathResource
is effectively a pure java.nio.path.Path
based alternative to FileSystemResource
with
different createRelative
behavior.
ServletContextResource
这是一个适用于 ServletContext
资源的 Resource
实现,可以解释相关 Web 应用程序根目录内的相对路径。
This is a Resource
implementation for ServletContext
resources that interprets
relative paths within the relevant web application’s root directory.
它始终支持流访问和 URL 访问,但仅在 Web 应用程序存档已展开且该资源实际上存在于文件系统上时才允许 java.io.File
访问。它是否展开并存在于文件系统上,或者是否直接从 JAR 或数据库等其他地方(这是可以想象的)进行访问,实际上取决于 Servlet 容器。
It always supports stream access and URL access but allows java.io.File
access only
when the web application archive is expanded and the resource is physically on the
filesystem. Whether or not it is expanded and on the filesystem or accessed
directly from the JAR or somewhere else like a database (which is conceivable) is actually
dependent on the Servlet container.
InputStreamResource
InputStreamResource
是给定 InputStream
的 Resource
实现。仅当没有特定的 Resource
实现适用时才应该使用它。具体而言,在可能的情况下,优先使用 ByteArrayResource
或任何基于文件的 Resource
实现。
An InputStreamResource
is a Resource
implementation for a given InputStream
. It
should be used only if no specific Resource
implementation is applicable. In
particular, prefer ByteArrayResource
or any of the file-based Resource
implementations where possible.
与其他 Resource
实现不同,这是一个已经打开的资源的描述符。因此,它从 isOpen()
返回 true
。如果您需要将资源描述符保留在某个地方或需要多次读取流,请不要使用它。
In contrast to other Resource
implementations, this is a descriptor for an
already-opened resource. Therefore, it returns true
from isOpen()
. Do not use it if
you need to keep the resource descriptor somewhere or if you need to read a stream
multiple times.
ByteArrayResource
这是一个给定字节数组的 Resource
实现。它为给定的字节数组创建 ByteArrayInputStream
。
This is a Resource
implementation for a given byte array. It creates a
ByteArrayInputStream
for the given byte array.
这对于从任何给定的字节数组加载内容非常有用,而无需使用一次性 InputStreamResource
。
It is useful for loading content from any given byte array without having to resort to a
single-use InputStreamResource
.
The ResourceLoader
Interface
ResourceLoader
接口旨在由可以返回(即,加载)Resource
实例的对象实现。以下列表显示了 ResourceLoader
接口定义:
The ResourceLoader
interface is meant to be implemented by objects that can return
(that is, load) Resource
instances. The following listing shows the ResourceLoader
interface definition:
public interface ResourceLoader {
Resource getResource(String location);
ClassLoader getClassLoader();
}
所有应用程序上下文都实现了 ResourceLoader
接口。因此,可以使用所有应用程序上下文来获取 Resource
实例。
All application contexts implement the ResourceLoader
interface. Therefore, all
application contexts may be used to obtain Resource
instances.
当您在特定应用程序上下文中调用 getResource()
,并且指定的 location path 没有特定前缀时,您会得到一个适合于特定应用程序上下文的 Resource
类型。例如,假设运行了以下代码段来针对 ClassPathXmlApplicationContext
实例:
When you call getResource()
on a specific application context, and the location path
specified doesn’t have a specific prefix, you get back a Resource
type that is
appropriate to that particular application context. For example, assume the following
snippet of code was run against a ClassPathXmlApplicationContext
instance:
-
Java
-
Kotlin
Resource template = ctx.getResource("some/resource/path/myTemplate.txt");
val template = ctx.getResource("some/resource/path/myTemplate.txt")
对于 ClassPathXmlApplicationContext
,该代码返回 ClassPathResource
。如果针对 FileSystemXmlApplicationContext
实例运行相同的方法,它将返回 FileSystemResource
。对于 WebApplicationContext
,它将返回 ServletContextResource
。它同样会为每个上下文返回适当的对象。
Against a ClassPathXmlApplicationContext
, that code returns a ClassPathResource
. If
the same method were run against a FileSystemXmlApplicationContext
instance, it would
return a FileSystemResource
. For a WebApplicationContext
, it would return a
ServletContextResource
. It would similarly return appropriate objects for each context.
因此,您可以以适合特定应用程序上下文的样式加载资源。
As a result, you can load resources in a fashion appropriate to the particular application context.
另一方面,您还可以强制使用 ClassPathResource
,而不管应用程序上下文类型如何,方法是指定特殊的前缀 classpath:
,如下例所示:
On the other hand, you may also force ClassPathResource
to be used, regardless of the
application context type, by specifying the special classpath:
prefix, as the following
example shows:
-
Java
-
Kotlin
Resource template = ctx.getResource("classpath:some/resource/path/myTemplate.txt");
val template = ctx.getResource("classpath:some/resource/path/myTemplate.txt")
同样,您可以通过指定任何标准的 java.net.URL
前缀来强制使用 UrlResource
。以下示例使用前缀 file
和 https
:
Similarly, you can force a UrlResource
to be used by specifying any of the standard
java.net.URL
prefixes. The following examples use the file
and https
prefixes:
-
Java
-
Kotlin
Resource template = ctx.getResource("file:///some/resource/path/myTemplate.txt");
val template = ctx.getResource("file:///some/resource/path/myTemplate.txt")
-
Java
-
Kotlin
Resource template = ctx.getResource("https://myhost.com/resource/path/myTemplate.txt");
val template = ctx.getResource("https://myhost.com/resource/path/myTemplate.txt")
下表总结了将 String
对象转换为 Resource
对象的策略:
The following table summarizes the strategy for converting String
objects to Resource
objects:
Prefix | Example | Explanation |
---|---|---|
classpath: |
|
Loaded from the classpath. |
file: |
|
Loaded as a |
https: |
|
Loaded as a |
(none) |
|
Depends on the underlying |
The ResourcePatternResolver
Interface
ResourcePatternResolver
接口是对 ResourceLoader
接口的扩展,它定义了将位置模式(例如,Ant 风格路径模式)解析为 Resource
对象的策略。
The ResourcePatternResolver
interface is an extension to the ResourceLoader
interface
which defines a strategy for resolving a location pattern (for example, an Ant-style path
pattern) into Resource
objects.
public interface ResourcePatternResolver extends ResourceLoader {
String CLASSPATH_ALL_URL_PREFIX = "classpath*:";
Resource[] getResources(String locationPattern) throws IOException;
}
正如上面所见,此接口还定义了一个针对类路径中的所有匹配资源特殊 classpath*:
资源前缀。请注意,在这种情况下,资源位置应为不含占位符的路径,例如 classpath*:/config/beans.xml
。JAR 文件或类路径中的不同目录可以包含具有相同路径和名称的多文件。有关使用 classpath*:
资源前缀通配符支持的更多详细信息,请参阅 Wildcards in Application Context Constructor Resource Paths 及其子部分。
As can be seen above, this interface also defines a special classpath*:
resource prefix
for all matching resources from the class path. Note that the resource location is
expected to be a path without placeholders in this case — for example,
classpath*:/config/beans.xml
. JAR files or different directories in the class path can
contain multiple files with the same path and the same name. See
Wildcards in Application Context Constructor Resource Paths and its subsections for further details
on wildcard support with the classpath*:
resource prefix.
可以检查传入 ResourceLoader
(例如,通过 ResourceLoaderAware
语义提供的 ResourceLoader
)是否也实现了此扩展接口。
A passed-in ResourceLoader
(for example, one supplied via
ResourceLoaderAware
semantics) can be checked whether
it implements this extended interface too.
PathMatchingResourcePatternResolver
是一个独立实现,可以在 ApplicationContext
外部使用,它也由 ResourceArrayPropertyEditor
用于填充 Resource[]
bean 属性。PathMatchingResourcePatternResolver
能够将指定资源位置路径解析为一个或多个匹配的 Resource
对象。源路径可能是简单路径,它具有与目标 Resource
对应的一对一映射,或者可以包含特殊 classpath*:
前缀和/或内部 Ant 样式正则表达式(使用 Spring 的 org.springframework.util.AntPathMatcher
实用程序进行匹配)。后两者实际上都是通配符。
PathMatchingResourcePatternResolver
is a standalone implementation that is usable
outside an ApplicationContext
and is also used by ResourceArrayPropertyEditor
for
populating Resource[]
bean properties. PathMatchingResourcePatternResolver
is able to
resolve a specified resource location path into one or more matching Resource
objects.
The source path may be a simple path which has a one-to-one mapping to a target
Resource
, or alternatively may contain the special classpath*:
prefix and/or internal
Ant-style regular expressions (matched using Spring’s
org.springframework.util.AntPathMatcher
utility). Both of the latter are effectively
wildcards.
任何标准 The default |
The ResourceLoaderAware
Interface
ResourceLoaderAware
接口是一个特殊的回调接口,用于标识希望提供 ResourceLoader
引用。以下列表显示了 ResourceLoaderAware
接口的定义:
The ResourceLoaderAware
interface is a special callback interface which identifies
components that expect to be provided a ResourceLoader
reference. The following listing
shows the definition of the ResourceLoaderAware
interface:
public interface ResourceLoaderAware {
void setResourceLoader(ResourceLoader resourceLoader);
}
当一个类实现 ResourceLoaderAware
并部署到应用程序上下文中(作为 Spring 管理的 bean)时,应用程序上下体会将其识别为 ResourceLoaderAware
。然后,应用程序上下文调用 setResourceLoader(ResourceLoader)
,将自身作为参数提供(请记住,Spring 中的所有应用程序上下文都实现了 ResourceLoader
接口)。
When a class implements ResourceLoaderAware
and is deployed into an application context
(as a Spring-managed bean), it is recognized as ResourceLoaderAware
by the application
context. The application context then invokes setResourceLoader(ResourceLoader)
,
supplying itself as the argument (remember, all application contexts in Spring implement
the ResourceLoader
interface).
由于 ApplicationContext
是一个 ResourceLoader
,因此 bean 也可以实现 ApplicationContextAware
接口,并使用提供的应用程序上下文直接加载资源。但是,通常情况下,如果你只需要它,最好使用专门的 ResourceLoader
接口。代码只会与资源加载接口(可以认为是实用程序接口)耦合,而不会与整个 Spring ApplicationContext
接口耦合。
Since an ApplicationContext
is a ResourceLoader
, the bean could also implement the
ApplicationContextAware
interface and use the supplied application context directly to
load resources. However, in general, it is better to use the specialized ResourceLoader
interface if that is all you need. The code would be coupled only to the resource loading
interface (which can be considered a utility interface) and not to the whole Spring
ApplicationContext
interface.
在应用程序组件中,你还可以依赖 ResourceLoader
的自动装配,而不是实现 ResourceLoaderAware
接口。traditional constructor
和 byType
自动装配模式(如 Autowiring Collaborators 中所述)能够分别为构造函数参数或 setter 方法参数提供 ResourceLoader
。为了获得更大的灵活性(包括自动装配字段和多参数方法的能力),请考虑使用基于注释的自动装配功能。在这种情况下,ResourceLoader
被自动装配到字段、构造函数参数或方法参数中,该字段、参数或方法期待 ResourceLoader
类型,只要有问题的字段、构造函数或方法带有 @Autowired
注释。有关更多信息,请参阅 Using @Autowired
。
In application components, you may also rely upon autowiring of the ResourceLoader
as
an alternative to implementing the ResourceLoaderAware
interface. The traditional
constructor
and byType
autowiring modes (as described in Autowiring Collaborators)
are capable of providing a ResourceLoader
for either a constructor argument or a
setter method parameter, respectively. For more flexibility (including the ability to
autowire fields and multiple parameter methods), consider using the annotation-based
autowiring features. In that case, the ResourceLoader
is autowired into a field,
constructor argument, or method parameter that expects the ResourceLoader
type as long
as the field, constructor, or method in question carries the @Autowired
annotation.
For more information, see Using @Autowired
.
要加载一个或多个 |
To load one or more |
Resources as Dependencies
如果 bean 本身要通过某种动态过程来确定和提供资源路径,那么 bean 使用 ResourceLoader
或 ResourcePatternResolver
接口来加载资源可能是有道理的。例如,考虑加载某种模板,其中所需的特定资源取决于用户角色。如果资源是静态的,那么完全取消使用 ResourceLoader
接口(或 ResourcePatternResolver
接口)是有道理的,让 bean 公开它需要的 Resource
属性,并期望它们被注入到其中。
If the bean itself is going to determine and supply the resource path through some sort
of dynamic process, it probably makes sense for the bean to use the ResourceLoader
or
ResourcePatternResolver
interface to load resources. For example, consider the loading
of a template of some sort, where the specific resource that is needed depends on the
role of the user. If the resources are static, it makes sense to eliminate the use of the
ResourceLoader
interface (or ResourcePatternResolver
interface) completely, have the
bean expose the Resource
properties it needs, and expect them to be injected into it.
使注入这些属性变得轻而易举的是,所有应用程序上下文都会注册并使用一个特殊的 JavaBeans PropertyEditor
,它可以将 String
路径转换为 Resource
对象。例如,以下 MyBean
类有一个 template
属性,类型为 Resource
。
What makes it trivial to then inject these properties is that all application contexts
register and use a special JavaBeans PropertyEditor
, which can convert String
paths
to Resource
objects. For example, the following MyBean
class has a template
property of type Resource
.
-
Java
-
Kotlin
public class MyBean {
private Resource template;
public setTemplate(Resource template) {
this.template = template;
}
// ...
}
class MyBean(var template: Resource)
在 XML 配置文件中,template
属性可以使用该资源的简单字符串进行配置,如下例所示:
In an XML configuration file, the template
property can be configured with a simple
string for that resource, as the following example shows:
<bean id="myBean" class="example.MyBean">
<property name="template" value="some/resource/path/myTemplate.txt"/>
</bean>
请注意,资源路径没有前缀。因此,由于应用程序上下文本身将用作 ResourceLoader
,因此该资源将通过 ClassPathResource
、FileSystemResource
或 ServletContextResource
加载,具体取决于应用程序上下文的具体类型。
Note that the resource path has no prefix. Consequently, because the application context
itself is going to be used as the ResourceLoader
, the resource is loaded through a
ClassPathResource
, a FileSystemResource
, or a ServletContextResource
, depending on
the exact type of the application context.
如果你需要强制使用特定的 Resource
类型,则可以使用前缀。以下两个示例展示了如何强制使用 ClassPathResource
和 UrlResource
(后者用于访问文件系统中的文件):
If you need to force a specific Resource
type to be used, you can use a prefix. The
following two examples show how to force a ClassPathResource
and a UrlResource
(the
latter being used to access a file in the filesystem):
<property name="template" value="classpath:some/resource/path/myTemplate.txt">
<property name="template" value="file:///some/resource/path/myTemplate.txt"/>
如果 MyBean
类被重构以与注释驱动的配置一起使用,则 myTemplate.txt
的路径可以存储在名为 template.path
的键下——例如,在为 Spring Environment
提供的属性文件中(参见 Environment Abstraction )。然后可以通过使用属性占位符(请参见 Using @Value
)通过 @Value
注释来引用模板路径。Spring 会将模板路径的值检出为字符串,并且特殊的 PropertyEditor
将把字符串转换为要注入到 MyBean
构造函数中的 Resource
对象。以下示例演示了如何实现这一点。
If the MyBean
class is refactored for use with annotation-driven configuration, the
path to myTemplate.txt
can be stored under a key named template.path
— for example,
in a properties file made available to the Spring Environment
(see
Environment Abstraction). The template path can then be referenced via the @Value
annotation using a property placeholder (see Using @Value
). Spring will
retrieve the value of the template path as a string, and a special PropertyEditor
will
convert the string to a Resource
object to be injected into the MyBean
constructor.
The following example demonstrates how to achieve this.
-
Java
-
Kotlin
@Component
public class MyBean {
private final Resource template;
public MyBean(@Value("${template.path}") Resource template) {
this.template = template;
}
// ...
}
@Component
class MyBean(@Value("\${template.path}") private val template: Resource)
如果我们希望支持在 classpath 中多个位置发现多个模板——例如,在 classpath 中的多个 jar 中——我们可以使用特殊 classpath*:
前缀和通配符将 templates.path
键定义为 classpath*:/config/templates/*.txt
。如果我们重新定义 MyBean
类如下所示,Spring 会将模板路径模式转换为可以注入到 MyBean
构造函数中的 Resource
对象数组。
If we want to support multiple templates discovered under the same path in multiple
locations in the classpath — for example, in multiple jars in the classpath — we can
use the special classpath*:
prefix and wildcarding to define a templates.path
key as
classpath*:/config/templates/*.txt
. If we redefine the MyBean
class as follows,
Spring will convert the template path pattern into an array of Resource
objects that
can be injected into the MyBean
constructor.
-
Java
-
Kotlin
@Component
public class MyBean {
private final Resource[] templates;
public MyBean(@Value("${templates.path}") Resource[] templates) {
this.templates = templates;
}
// ...
}
@Component
class MyBean(@Value("\${templates.path}") private val templates: Resource[])
Application Contexts and Resource Paths
本节介绍如何使用资源创建应用程序上下文,包括使用 XML 的快捷方式、如何使用通配符以及其他详细信息。
This section covers how to create application contexts with resources, including shortcuts that work with XML, how to use wildcards, and other details.
Constructing Application Contexts
应用程序上下文构造函数(对于特定的应用程序上下文类型)通常使用字符串或字符串数组作为资源(例如构成上下文定义的 XML 文件)的位置路径。
An application context constructor (for a specific application context type) generally takes a string or array of strings as the location paths of the resources, such as XML files that make up the definition of the context.
如果这样的位置路径没有前缀,则从该路径构建并用于加载 bean 定义的特定 Resource
类型取决于特定应用程序上下文,并且适合该上下文。例如,考虑以下示例,它创建了一个 ClassPathXmlApplicationContext
:
When such a location path does not have a prefix, the specific Resource
type built from
that path and used to load the bean definitions depends on and is appropriate to the
specific application context. For example, consider the following example, which creates a
ClassPathXmlApplicationContext
:
-
Java
-
Kotlin
ApplicationContext ctx = new ClassPathXmlApplicationContext("conf/appContext.xml");
val ctx = ClassPathXmlApplicationContext("conf/appContext.xml")
bean 定义从 classpath 加载,因为使用了 ClassPathResource
。但是,考虑以下示例,它创建了一个 FileSystemXmlApplicationContext
:
The bean definitions are loaded from the classpath, because a ClassPathResource
is
used. However, consider the following example, which creates a FileSystemXmlApplicationContext
:
-
Java
-
Kotlin
ApplicationContext ctx =
new FileSystemXmlApplicationContext("conf/appContext.xml");
val ctx = FileSystemXmlApplicationContext("conf/appContext.xml")
现在,bean 定义从文件系统位置加载(在本例中,相对于当前工作目录)。
Now the bean definitions are loaded from a filesystem location (in this case, relative to the current working directory).
请注意,在位置路径上使用特殊 classpath
前缀或标准 URL 前缀会覆盖创建用于加载 bean 定义的默认 Resource
类型。考虑以下示例:
Note that the use of the special classpath
prefix or a standard URL prefix on the
location path overrides the default type of Resource
created to load the bean
definitions. Consider the following example:
-
Java
-
Kotlin
ApplicationContext ctx =
new FileSystemXmlApplicationContext("classpath:conf/appContext.xml");
val ctx = FileSystemXmlApplicationContext("classpath:conf/appContext.xml")
使用 FileSystemXmlApplicationContext
从 classpath 加载 bean 定义。但是,它仍然是 FileSystemXmlApplicationContext
。如果随后将其用作 ResourceLoader
,那么任何没有前缀的路径仍然会被视为文件系统路径。
Using FileSystemXmlApplicationContext
loads the bean definitions from the classpath.
However, it is still a FileSystemXmlApplicationContext
. If it is subsequently used as a
ResourceLoader
, any unprefixed paths are still treated as filesystem paths.
Constructing ClassPathXmlApplicationContext
Instances — Shortcuts
ClassPathXmlApplicationContext
公开了多个构造函数,以实现方便的实例化。基本思想是你可以提供一个只包含 XML 文件本身的文件名(没有前导路径信息)的字符串数组,还可以提供一个 Class
。然后,ClassPathXmlApplicationContext
从提供的类派生出路径信息。
The ClassPathXmlApplicationContext
exposes a number of constructors to enable
convenient instantiation. The basic idea is that you can supply merely a string array
that contains only the filenames of the XML files themselves (without the leading path
information) and also supply a Class
. The ClassPathXmlApplicationContext
then derives
the path information from the supplied class.
考虑以下目录布局:
Consider the following directory layout:
com/ example/ services.xml repositories.xml MessengerService.class
以下示例展示了如何实例化一个 ClassPathXmlApplicationContext
实例,该实例由名为 services.xml
和 repositories.xml
(位于 classpath 中)的文件中定义的 bean 组成:
The following example shows how a ClassPathXmlApplicationContext
instance composed of
the beans defined in files named services.xml
and repositories.xml
(which are on the
classpath) can be instantiated:
-
Java
-
Kotlin
ApplicationContext ctx = new ClassPathXmlApplicationContext(
new String[] {"services.xml", "repositories.xml"}, MessengerService.class);
val ctx = ClassPathXmlApplicationContext(arrayOf("services.xml", "repositories.xml"), MessengerService::class.java)
请参阅 ClassPathXmlApplicationContext
javadoc 以了解有关各种构造函数的详情。
See the ClassPathXmlApplicationContext
javadoc for details on the various constructors.
Wildcards in Application Context Constructor Resource Paths
应用程序上下文构造函数值中的资源路径可以是简单的路径(如前面所示),每个路径与目标`Resource`一一对应,或者包含特殊的`classpath*:`前缀或内部 Ant 风格模式(通过使用 Spring 的`PathMatcher`实用程序进行匹配)。后两者实际上都是通配符。
The resource paths in application context constructor values may be simple paths (as
shown earlier), each of which has a one-to-one mapping to a target Resource
or,
alternately, may contain the special classpath*:
prefix or internal Ant-style patterns
(matched by using Spring’s PathMatcher
utility). Both of the latter are effectively
wildcards.
使用此机制的一种情况是需要执行组件式应用程序程序集的时候。所有组件都可以将上下文定义片段“发布”到已知的位置路径,并且当使用带有`classpath*:`前缀的相同路径创建最终的应用程序上下文时,将自动选取所有组件片段。
One use for this mechanism is when you need to do component-style application assembly. All
components can publish context definition fragments to a well-known location path, and,
when the final application context is created using the same path prefixed with
classpath*:
, all component fragments are automatically picked up.
请注意,此通配符特定于应用程序上下文中使用资源路径(或直接使用`PathMatcher`实用程序类层次结构),并在构建时解析。它与`Resource`类型本身无关。无法使用`classpath*:`前缀来构建实际的`Resource`,因为资源一次只指向一个资源。
Note that this wildcarding is specific to the use of resource paths in application context
constructors (or when you use the PathMatcher
utility class hierarchy directly) and is
resolved at construction time. It has nothing to do with the Resource
type itself.
You cannot use the classpath*:
prefix to construct an actual Resource
, as
a resource points to just one resource at a time.
Ant-style Patterns
路径位置可以包含 Ant 风格模式,如下例所示:
Path locations can contain Ant-style patterns, as the following example shows:
/WEB-INF/-context.xml com/mycompany//applicationContext.xml file:C:/some/path/-context.xml classpath:com/mycompany//applicationContext.xml
当路径位置包含 Ant 风格模式时,解析器将遵循一个更复杂的程序来尝试解析通配符。它会为该路径(直到最后一个非通配符段)生成`Resource`,并从中获取 URL。如果此 URL 不是`jar:`URL 或特定于容器的变体(例如 WebLogic 中的`zip:`、WebSphere 中的`wsjar`等),将从该 URL 获取`java.io.File`并用它来遍历文件系统以解析通配符。对于 jar URL,解析器要么从中获取`java.net.JarURLConnection`,要么手动解析 jar URL,然后遍历 jar 文件的内容以解析通配符。
When the path location contains an Ant-style pattern, the resolver follows a more complex
procedure to try to resolve the wildcard. It produces a Resource
for the path up to the
last non-wildcard segment and obtains a URL from it. If this URL is not a jar:
URL or
container-specific variant (such as zip:
in WebLogic, wsjar
in WebSphere, and so on),
a java.io.File
is obtained from it and used to resolve the wildcard by traversing the
filesystem. In the case of a jar URL, the resolver either gets a
java.net.JarURLConnection
from it or manually parses the jar URL and then traverses the
contents of the jar file to resolve the wildcards.
Implications on Portability
如果指定路径已经是`file`URL(隐式是因为基本`ResourceLoader`是文件系统资源加载器或显式),则保证以完全可移植的方式使用通配符。
If the specified path is already a file
URL (either implicitly because the base
ResourceLoader
is a filesystem one or explicitly), wildcarding is guaranteed to
work in a completely portable fashion.
如果指定路径是`classpath`位置,则解析器必须通过进行`Classloader.getResource()调用来获取最后一个非通配符路径段的 URL。由于这只是路径的一个节点(而不是末尾的文件),因此实际上是未定义的(在`ClassLoader`javadoc 中),在这种情况下将返回哪种类型的 URL。实际上,它始终是表示目录的`java.io.File
(其中类路径资源解析到文件系统位置)或某种 jar URL(其中类路径资源解析到 jar 位置)。尽管如此,此操作仍存在可移植性问题。
If the specified path is a classpath
location, the resolver must obtain the last
non-wildcard path segment URL by making a Classloader.getResource()
call. Since this
is just a node of the path (not the file at the end), it is actually undefined (in the
ClassLoader
javadoc) exactly what sort of a URL is returned in this case. In practice,
it is always a java.io.File
representing the directory (where the classpath resource
resolves to a filesystem location) or a jar URL of some sort (where the classpath resource
resolves to a jar location). Still, there is a portability concern on this operation.
如果为最后一个非通配符段获取 jar URL,则解析器必须能够从中获取`java.net.JarURLConnection`或手动解析 jar URL,以便能够遍历 jar 的内容并解析通配符。这在大多数环境中有效,但在其他环境中会失败,我们强烈建议在依赖它之前彻底测试来自 jar 的资源的通配符解析。
If a jar URL is obtained for the last non-wildcard segment, the resolver must be able to
get a java.net.JarURLConnection
from it or manually parse the jar URL, to be able to
walk the contents of the jar and resolve the wildcard. This does work in most environments
but fails in others, and we strongly recommend that the wildcard resolution of resources
coming from jars be thoroughly tested in your specific environment before you rely on it.
The classpath*:
Prefix
构建基于 XML 的应用程序上下文时,位置字符串可以使用特殊的`classpath*:`前缀,如下例所示:
When constructing an XML-based application context, a location string may use the
special classpath*:
prefix, as the following example shows:
-
Java
-
Kotlin
ApplicationContext ctx =
new ClassPathXmlApplicationContext("classpath*:conf/appContext.xml");
val ctx = ClassPathXmlApplicationContext("classpath*:conf/appContext.xml")
此特殊前缀指定必须获取所有与给定名称匹配的类路径资源(在内部,这本质上是通过调用`ClassLoader.getResources(…)`实现的),然后合并以形成最终的应用程序上下文定义。
This special prefix specifies that all classpath resources that match the given name
must be obtained (internally, this essentially happens through a call to
ClassLoader.getResources(…)
) and then merged to form the final application
context definition.
通配符类路径依赖于基础 |
The wildcard classpath relies on the |
您还可以将`classpath*:`前缀与位置路径的其余部分中的`PathMatcher`模式结合使用(例如,classpath*:META-INF/*-beans.xml
)。在这种情况下,解析策略非常简单:对最后一个非通配符路径段使用`ClassLoader.getResources()`调用以获取类加载器层次结构中的所有匹配的资源,然后对每个资源均使用前面描述的相同`PathMatcher`解析策略进行通配符子路径解析。
You can also combine the classpath*:
prefix with a PathMatcher
pattern in the
rest of the location path (for example, classpath*:META-INF/*-beans.xml
). In this
case, the resolution strategy is fairly simple: A ClassLoader.getResources()
call is
used on the last non-wildcard path segment to get all the matching resources in the
class loader hierarchy and then, off each resource, the same PathMatcher
resolution
strategy described earlier is used for the wildcard subpath.
Other Notes Relating to Wildcards
请注意,`classpath*:`在与 Ant 风格模式结合使用时,仅在模式开始之前至少有一个根目录时才能可靠地工作,除非实际目标文件驻留在文件系统中。这意味着这样的模式`classpath*:*.xml`可能无法从 jar 文件的根目录检索文件,而只能从已展开目录的根目录检索文件。
Note that classpath*:
, when combined with Ant-style patterns, only works
reliably with at least one root directory before the pattern starts, unless the actual
target files reside in the file system. This means that a pattern such as
classpath*:*.xml
might not retrieve files from the root of jar files but rather only
from the root of expanded directories.
Spring 检索类路径条目的能力源自 JDK 的`ClassLoader.getResources()`方法,该方法仅为一个空字符串(表示要搜索的潜在根目录)返回文件系统位置。Spring 还评估`URLClassLoader`运行时配置和 jar 文件中的`java.class.path`清单,但这并不能保证达到可移植行为。
Spring’s ability to retrieve classpath entries originates from the JDK’s
ClassLoader.getResources()
method, which only returns file system locations for an
empty string (indicating potential roots to search). Spring evaluates
URLClassLoader
runtime configuration and the java.class.path
manifest in jar files
as well, but this is not guaranteed to lead to portable behavior.
类路径包的扫描需要类路径中存在相应的目录项。使用 Ant 构建 JAR 时,请勿激活 JAR 任务的`files-only`开关。此外,类路径目录在某些环境中可能不会根据安全策略公开——例如 JDK 1.7.0_45 及更高版本上的独立应用程序 (这需要在清单中设置“受信任库”。请参阅 https://stackoverflow.com/questions/19394570/java-jre-7u45-breaks-classloader-getresources)。 The scanning of classpath packages requires the presence of corresponding directory
entries in the classpath. When you build JARs with Ant, do not activate the 在 JDK 9 的模块路径(Jigsaw)上,Spring 的类路径扫描通常按预期执行。在此处将资源放入专门的目录也强烈推荐,这样可以避免使用前面提到的可移植性问题搜索 jar 文件的根级别。 On JDK 9’s module path (Jigsaw), Spring’s classpath scanning generally works as expected. Putting resources into a dedicated directory is highly recommendable here as well, avoiding the aforementioned portability problems with searching the jar file root level. |
如果要搜索的根包在多个类路径位置中可用,则使用`classpath:`资源的 Ant 风格模式并不能保证找到匹配的资源。考虑以下资源位置的示例:
Ant-style patterns with classpath:
resources are not guaranteed to find matching
resources if the root package to search is available in multiple classpath locations.
Consider the following example of a resource location:
com/mycompany/package1/service-context.xml
现在考虑可能有人用来尝试查找该文件的 Ant 风格路径:
Now consider an Ant-style path that someone might use to try to find that file:
classpath:com/mycompany/**/service-context.xml
这样的资源可能只存在于类路径中的一个位置,但是当使用如前例所示的路径来尝试解析时,解析器以`getResource("com/mycompany");`返回的(第一个)URL 为依据。如果这个基本包节点存在于多个`ClassLoader`位置,则所需的资源可能不存在于找到的第一个位置。因此,在这种情况下,您应该更喜欢将`classpath*:`与相同的 Ant 风格模式一起使用,该模式搜索包含`com.mycompany`基本包的所有类路径位置: classpath*:com/mycompany/**/service-context.xml
。
Such a resource may exist in only one location in the classpath, 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 desired resource may not exist in the first
location found. Therefore, in such cases you should prefer using classpath*:
with the
same Ant-style pattern, which searches all classpath locations that contain the
com.mycompany
base package: classpath*:com/mycompany/**/service-context.xml
.
FileSystemResource
Caveats
没有附加FileSystemApplicationContext(换句话说,当FileSystemApplicationContext不是实际ResourceLoader)时,将FileSystemResource视为您预期的那样处理绝对和相对路径。相对路径相对于当前工作目录,而绝对路径相对于文件系统的根目录。
A FileSystemResource
that is not attached to a FileSystemApplicationContext
(that
is, when a FileSystemApplicationContext
is not the actual ResourceLoader
) treats
absolute and relative paths as you would expect. Relative paths are relative to the
current working directory, while absolute paths are relative to the root of the
filesystem.
然而,出于向后兼容性(历史)原因,当FileSystemApplicationContext是ResourceLoader时,这是改变的。FileSystemApplicationContext强制所有附加的FileSystemResource实例将所有位置路径视为相对,无论它们是否以前置斜线开头。实际上,这意味着以下示例是等效的:
For backwards compatibility (historical) reasons however, this changes when the
FileSystemApplicationContext
is the ResourceLoader
. The
FileSystemApplicationContext
forces all attached FileSystemResource
instances
to treat all location paths as relative, whether they start with a leading slash or not.
In practice, this means the following examples are equivalent:
-
Java
-
Kotlin
ApplicationContext ctx =
new FileSystemXmlApplicationContext("conf/context.xml");
val ctx = FileSystemXmlApplicationContext("conf/context.xml")
-
Java
-
Kotlin
ApplicationContext ctx =
new FileSystemXmlApplicationContext("/conf/context.xml");
val ctx = FileSystemXmlApplicationContext("/conf/context.xml")
以下示例也是等效的(即使它们看起来不同也会有道理,因为一个情况是相对的,而另一个情况是绝对的):
The following examples are also equivalent (even though it would make sense for them to be different, as one case is relative and the other absolute):
-
Java
-
Kotlin
FileSystemXmlApplicationContext ctx = ...;
ctx.getResource("some/resource/path/myTemplate.txt");
val ctx: FileSystemXmlApplicationContext = ...
ctx.getResource("some/resource/path/myTemplate.txt")
-
Java
-
Kotlin
FileSystemXmlApplicationContext ctx = ...;
ctx.getResource("/some/resource/path/myTemplate.txt");
val ctx: FileSystemXmlApplicationContext = ...
ctx.getResource("/some/resource/path/myTemplate.txt")
实际上,如果您需要真正的绝对文件系统路径,则应避免将绝对路径与FileSystemResource或FileSystemXmlApplicationContext一起使用,并强制使用UrlResource,方法是使用file: URL 前缀。以下示例展示了如何执行此操作:
In practice, if you need true absolute filesystem paths, you should avoid using
absolute paths with FileSystemResource
or FileSystemXmlApplicationContext
and
force the use of a UrlResource
by using the file:
URL prefix. The following examples
show how to do so:
-
Java
-
Kotlin
// actual context type doesn't matter, the Resource will always be UrlResource
ctx.getResource("file:///some/resource/path/myTemplate.txt");
// actual context type doesn't matter, the Resource will always be UrlResource
ctx.getResource("file:///some/resource/path/myTemplate.txt")
-
Java
-
Kotlin
// force this FileSystemXmlApplicationContext to load its definition via a UrlResource
ApplicationContext ctx =
new FileSystemXmlApplicationContext("file:///conf/context.xml");
// force this FileSystemXmlApplicationContext to load its definition via a UrlResource
val ctx = FileSystemXmlApplicationContext("file:///conf/context.xml")