https://docs.spring.io/spring-framework/reference/core/resources.html
介绍
Java 标准的 java.net.URL
类和各种 URL 前缀的标准处理程序,不幸的是,对于所有访问底层资源的需要来说并不完全足够。例如,没有标准化的 URL 实现可以用来访问需要从类路径或相对于 ServletContext
获取的资源。虽然可以为专门的 URL 前缀注册新的处理程序(类似于现有的 http:
前缀的处理程序),但这通常相当复杂,而且 URL 接口仍然缺乏一些期望的功能,比如检查所指向资源是否存在的方法。
Resource 接口
Spring 的 Resource
接口位于 org.springframework.core.io.
包中,旨在提供一个更强大的接口来抽象化访问底层资源。下面的列表提供了 Resource
接口的概览。
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
接口的定义:
public interface InputStreamSource {
InputStream getInputStream() throws IOException;
}
Resource
接口中一些最重要的方法是:
getInputStream()
:定位并打开资源,返回一个用于从资源读取的InputStream
。预期每次调用都返回一个新的InputStream
。关闭流是调用者的责任。exists()
:返回一个boolean
,指示此资源是否实际以物理形式存在。isOpen()
:返回一个boolean
,指示此资源是否代表一个带有打开流的句柄。如果为true
,则InputStream
不能被多次读取,必须只读取一次然后关闭以避免资源泄漏。对于所有通常的资源实现,除了InputStreamResource
,都返回false
。getDescription()
:返回此资源的描述,用于在处理资源时输出错误信息。这通常是完全限定的文件名或资源的实际 URL。
其它方法允许你获取表示资源的实际 URL
或 File
对象(如果底层实现兼容并支持该功能)。
Resource
接口的一些实现还实现了扩展的 WritableResource
接口,用于支持向其写入的资源。
Spring 本身广泛使用 Resource
抽象,在许多方法签名中作为参数类型,当需要资源时。一些 Spring API 中的其它方法(如各种 ApplicationContext
实现的构造函数)接受一个 String,这个 String 以未修饰或简单形式用于创建适合该上下文实现的 Resource
,或者通过在 String 路径上添加特殊前缀,让调用者指定必须创建并使用特定的 Resource
实现。
尽管 Resource
接口在 Spring 中被广泛使用,但实际上它作为通用的工具类在你自己的代码中使用也非常方便,用于访问资源,即使你的代码不知道或不关心 Spring 的任何其它部分。虽然这样做会将你的代码与 Spring 耦合,但实际上它只与这一小套实用程序类耦合,这些类可以作为 URL 的更有能力的替代品,并且可以被视为与你为此目的使用的任何其它库等效。
Resource
抽象并不替换功能。它在可能的情况下包装功能。例如,UrlResource
包装了一个 URL
并使用被包装的 URL
来完成其工作。
内置的 Resource 实现
Spring 包含了几个内置的 Resource
实现:
UrlResource
ClassPathResource
FileSystemResource
PathResource
ServletContextResource
InputStreamResource
ByteArrayResource
UrlResource
UrlResource
包装了一个 java.net.URL
,可用于访问通常可以通过 URL 访问的任何对象,如文件、HTTPS 目标、FTP 目标等。所有 URL 都有标准化的字符串表示形式,以便使用适当的标准化前缀来区分不同的 URL 类型。这包括使用 file:
访问文件系统路径,https:
通过 HTTPS 协议访问资源,ftp:
通过 FTP 访问资源等。
UrlResource
是由 Java 代码通过显式使用 UrlResource
构造函数创建的,但当你调用一个接受字符串参数(意在表示路径)的 API 方法时,它通常会被隐式创建。对于后一种情况,一个 JavaBeans PropertyEditor
最终决定创建哪种类型的 Resource
。如果路径字符串包含一个众所周知的(至少对属性编辑器来说)前缀(如 classpath:
),它会为该前缀创建一个适当的专门化 Resource
。然而,如果它没有识别出前缀,它会假设字符串是一个标准的 URL 字符串并创建一个 UrlResource
。
ClassPathResource
这个类代表一个应该从类路径获取的资源。它使用线程上下文类加载器、给定的类加载器或给定的类来加载资源。
这个 Resource
实现支持解析为 java.io.File
,如果类路径资源驻留在文件系统中,但不支持驻留在 jar 中且未被(servlet 引擎或其它环境)扩展到文件系统的类路径资源的解析。为了解决这个问题,各种 Resource
实现总是支持解析为 java.net.URL
。
ClassPathResource
是由 Java 代码通过显式使用 ClassPathResource
构造函数创建的,但当你调用一个接受字符串参数(意在表示路径)的 API 方法时,它通常会被隐式创建。对于后一种情况,一个 JavaBeans PropertyEditor
识别字符串路径上的特殊前缀 classpath:
,并在那种情况下创建一个 ClassPathResource
。
FileSystemResource
这是针对 java.io.File
句柄的 Resource
实现。它还支持 java.nio.file.Path
句柄,应用 Spring 的标准基于字符串的路径转换,但通过 java.nio.file.Files
API 执行所有操作。对于纯 java.nio.path.Path
的支持,请使用 PathResource
代替。FileSystemResource
支持解析为 File
和 URL
。
PathResource
这是针对 java.nio.file.Path
句柄的 Resource
实现,通过 Path API 执行所有操作和转换。它支持解析为 File
和 URL
,并实现了扩展的 WritableResource
接口。PathResource
实际上是 FileSystemResource
的纯 java.nio.path.Path
基础替代品,具有不同的 createRelative
行为。
ServletContextResource
这是针对 ServletContext
资源的 Resource
实现,它在相关 Web 应用程序的根目录内解释相对路径。
它始终支持流访问和 URL 访问,但仅在 Web 应用程序存档被扩展且资源实际存在于文件系统上时才允许 java.io.File
访问。它是否被扩展并位于文件系统上,或者直接从 JAR 或其它地方(如数据库)访问,实际上取决于 Servlet 容器。
InputStreamResource
InputStreamResource
是针对给定 InputStream
的 Resource
实现。只有在没有特定的 Resource
实现适用时才应该使用它。特别是,在可能的情况下,优先使用 ByteArrayResource
或任何基于文件的 Resource
实现。
与其它 Resource
实现相比,这是一个已经打开的资源的描述符。因此,它会从 isOpen()
返回 true
。如果需要将资源描述符保存在某处或需要多次读取流,请不要使用它。
ByteArrayResource
这是针对给定字节数组的 Resource
实现。它为给定的字节数组创建一个ByteArrayInputStream
。
它对于从任何给定的字节数组加载内容非常有用,无需使用一次性的 InputStreamResource
。
ResourceLoader 接口
ResourceLoader
接口旨在由能够返回(即加载)Resource
实例的对象实现。以下列表显示了 ResourceLoader
接口定义:
public interface ResourceLoader {
Resource getResource(String location);
ClassLoader getClassLoader();
}
所有的应用上下文都实现了 ResourceLoader
接口。因此,所有应用上下文都可以用来获取 Resource
实例。
当在特定的应用上下文上调用 getResource()
,并且指定的位置路径没有特定的前缀时,将获得适合该特定应用上下文的 Resource
类型。例如,假设以下代码片段是针对 ClassPathXmlApplicationContext
实例运行的:
Resource template = ctx.getResource("some/resource/path/myTemplate.txt");
针对 ClassPathXmlApplicationContext
,该代码返回一个 ClassPathResource
。如果相同的方法在 FileSystemXmlApplicationContext
实例上运行,它将返回一个 FileSystemResource
。对于 WebApplicationContext
,它将返回一个 ServletContextResource
。它也会类似地为每个上下文返回适当的对象。
因此,可以按照适合特定应用上下文的方式加载资源。
另一方面,也可以通过指定特殊的 classpath:
前缀来强制使用 ClassPathResource
,无论应用上下文类型如何,如下例所示:
Resource template = ctx.getResource("classpath:some/resource/path/myTemplate.txt");
类似地,可以通过指定任何标准的 java.net.URL
前缀来强制使用 UrlResource
。以下示例使用 file
和 https
前缀:
Resource template = ctx.getResource("file:///some/resource/path/myTemplate.txt");
Resource template = ctx.getResource("https://myhost.com/resource/path/myTemplate.txt");
下表总结了将 String 对象转换为 Resource
对象的策略:
ResourcePatternResolver 接口
ResourcePatternResolver
接口是 ResourceLoader
接口的扩展,它定义了将位置模式(例如,Ant 风格的路径模式)解析为 Resource
对象的策略。
public interface ResourcePatternResolver extends ResourceLoader {
String CLASSPATH_ALL_URL_PREFIX = "classpath*:";
Resource[] getResources(String locationPattern) throws IOException;
}
如上所示,这个接口还定义了一个特殊的 classpath*:
资源前缀,用于从类路径中匹配所有资源。请注意,在这种情况下,资源位置应该是一个没有占位符的路径——例如,classpath*:/config/beans.xml
。JAR 文件或类路径中的不同目录可以包含具有相同路径和名称的多个文件。
传入的 ResourceLoader
(例如,通过 ResourceLoaderAware
语义提供的)可以检查它是否也实现了这个扩展接口。
PathMatchingResourcePatternResolver
是一个独立的实现,可以在 ApplicationContext
之外使用,也被 ResourceArrayPropertyEditor
用于填充 Resource[]
类型的 bean 属性。PathMatchingResourcePatternResolver
能够将指定的资源位置路径解析为一个或多个匹配的 Resource
对象。源路径可以是与目标 Resource
一一对应的简单路径,或者可以包含特殊的 classpath*:
前缀和/或内部 Ant 风格的正则表达式(使用 Spring 的 org.springframework.util.AntPathMatcher
工具进行匹配)。后两者实际上是通配符。
任何标准 ApplicationContext
中的默认 ResourceLoader
实际上是 PathMatchingResourcePatternResolver
的一个实例,它实现了 ResourcePatternResolver
接口。对于 ApplicationContext
实例本身也是如此,它也实现了 ResourcePatternResolver
接口,并将任务委托给默认的 PathMatchingResourcePatternResolver
。
ResourceLoaderAware 接口
ResourceLoaderAware
接口是一个特殊的回调接口,用于标识期望提供 ResourceLoader
引用的组件。以下列表显示了 ResourceLoaderAware
接口的定义:
public interface ResourceLoaderAware {
void setResourceLoader(ResourceLoader resourceLoader);
}
当一个类实现了 ResourceLoaderAware
并将其部署到应用上下文(作为 Spring 管理的 bean)时,它会被应用上下文识别为 ResourceLoaderAware
。然后,应用上下文调用 setResourceLoader(ResourceLoader)
方法,将自己作为参数传入(记住,Spring 中的所有应用上下文都实现了 ResourceLoader
接口)。
由于 ApplicationContext
是一个 ResourceLoader
,bean 也可以实现 ApplicationContextAware
接口,并直接使用提供的应用上下文来加载资源。然而,通常情况下,如果只需要加载资源,最好使用专门的 ResourceLoader
接口。这样代码只与资源加载接口(可以视为一个实用接口)耦合,而不是整个 Spring ApplicationContext
接口。
在应用组件中,也可以依赖于 ResourceLoader
的自动装配,作为实现 ResourceLoaderAware
接口的替代方案。传统的constructor
和 byType
自动装配模式能够分别为构造函数参数或 setter 方法参数提供 ResourceLoader
。为了更大的灵活性(包括能够自动装配字段和多参数方法),可以考虑使用基于注解的自动装配特性。在这种情况下,只要字段、构造函数或方法带有 @Autowired
注解,ResourceLoader
就会自动装配到期望 ResourceLoader
类型的字段、构造函数参数或方法参数中。
要为包含通配符的资源路径或使用特殊的 classpath*:
资源前缀加载一个或多个 Resource
对象,请考虑将 ResourcePatternResolver
的实例自动装配到你的应用组件中,而不是 ResourceLoader
。
Resources 作为依赖
如果 bean 本身要通过某种动态过程确定并提供资源路径,那么让 bean 使用 ResourceLoader
或 ResourcePatternResolver
接口来加载资源可能是有意义的。例如,考虑加载某种模板,其中所需的具体资源取决于用户的角色。如果资源是静态的,那么完全可以不用 ResourceLoader
接口(或 ResourcePatternResolver
接口),让 bean 暴露它需要的 Resource
属性,并期望它们被注入到 bean 中。
使得注入这些属性变得简单的是,所有应用上下文都注册并使用了一个特殊的 JavaBeans PropertyEditor
,它可以将字符串路径转换为 Resource
对象。例如,下面的 MyBean
类有一个类型为 Resource
的 template
属性。
public class MyBean {
private Resource template;
public setTemplate(Resource template) {
this.template = template;
}
// ...
}
在 XML 配置文件中,可以使用资源的简单字符串来配置 template
属性,如下例所示:
<bean id="myBean" class="example.MyBean">
<property name="template" value="some/resource/path/myTemplate.txt"/>
</bean>
资源路径没有前缀。因此,由于应用上下文本身将用作 ResourceLoader
,根据应用上下文的确切类型,资源将通过 ClassPathResource
、FileSystemResource
或 ServletContextResource
加载。
如果需要强制使用特定的 Resource
类型,可以使用前缀。以下两个示例展示了如何强制使用 ClassPathResource
和 UrlResource
(后者用于访问文件系统中的文件):
<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
(使用。然后可以通过 @Value
注解引用模板路径,使用属性占位符。Spring 将检索模板路径的值作为字符串,一个特殊的 PropertyEditor
会将字符串转换为 Resource
对象,以便注入到 MyBean
构造函数中。以下示例演示了如何实现这一点。
@Component
public class MyBean {
private final Resource template;
public MyBean(@Value("${template.path}") Resource template) {
this.template = template;
}
// ...
}
如果我们想要在类路径的多个位置支持在同一路径下发现的多个模板——例如,在类路径中的多个 jar 文件中——我们可以使用特殊的 classpath*:
前缀和通配符来定义一个 templates.path
键,如 classpath*:/config/templates/*.txt
。如果我们重新定义 MyBean
类如下,Spring 将把模板路径模式转换为一个 Resource
对象数组,这些对象可以被注入到 MyBean
构造函数中。
@Component
public class MyBean {
private final Resource[] templates;
public MyBean(@Value("${templates.path}") Resource[] templates) {
this.templates = templates;
}
// ...
}
应用上下文和 Resource 路径
本节涵盖了如何创建带有资源的应用上下文,包括与 XML 配合使用的快捷方式、如何使用通配符以及其它细节。
构建应用上下文
应用上下文构造函数(针对特定的应用上下文类型)通常接受一个字符串或字符串数组作为资源的位置路径,例如构成上下文定义的 XML 文件。
当这样的位置路径没有前缀时,从该路径构建的特定 Resource
类型用于加载 bean 定义,取决于并适用于特定的应用上下文。例如,考虑以下示例,它创建了一个ClassPathXmlApplicationContext
:
ApplicationContext ctx = new ClassPathXmlApplicationContext("conf/appContext.xml");
bean 定义是从类路径加载的,因为使用了 ClassPathResource
。然而,考虑以下示例,它创建了一个 FileSystemXmlApplicationContext
:
ApplicationContext ctx =
new FileSystemXmlApplicationContext("conf/appContext.xml");
现在,bean 定义是从文件系统位置加载的(在本例中,相对于当前工作目录)。
请注意,位置路径上使用特殊的classpath
前缀或标准 URL 前缀会覆盖创建用于加载 bean 定义的默认 Resource
类型。考虑以下示例:
ApplicationContext ctx =
new FileSystemXmlApplicationContext("classpath:conf/appContext.xml");
使用 FileSystemXmlApplicationContext
从类路径加载 bean 定义。然而,它仍然是一个 FileSystemXmlApplicationContext
。如果它随后被用作 ResourceLoader
,任何未加前缀的路径仍被视为文件系统路径。
构建 ClassPathXmlApplicationContext 实例——快捷方式
ClassPathXmlApplicationContext
提供了多个构造函数,以便于实例化。基本思想是,你可以仅提供一个字符串数组,其中包含 XML 文件的文件名(没有前导路径信息),并且还提供一个 Class
。然后,ClassPathXmlApplicationContext
从提供的类中派生路径信息。
考虑以下目录结构:
com/
example/
services.xml
repositories.xml
MessengerService.class
以下示例展示了如何实例化一个 ClassPathXmlApplicationContext
实例,该实例由名为 services.xml
和 repositories.xml
的文件中定义的 beans 组成(这些文件位于类路径上):
ApplicationContext ctx = new ClassPathXmlApplicationContext(
new String[] {"services.xml", "repositories.xml"}, MessengerService.class);
用上下文构造函数资源路径中的通配符
应用上下文构造函数值中的资源路径可以是简单路径(如前所示),每个路径都与目标 Resource
有一对一的映射,或者可以包含特殊的 classpath*:
前缀或内部 Ant 风格的模式(通过使用 Spring 的 PathMatcher
工具进行匹配)。后两者实际上都是通配符。
这种机制的一个用途是当你需要进行组件式应用程序组装时。所有组件都可以将上下文定义片段发布到众所周知的位置路径,当最终的应用程序上下文使用相同的路径创建,并在前面加上 classpath*:
前缀时,所有组件片段都会自动被自动加载。
这种通配符特定于在应用上下文构造函数中使用资源路径时(或直接使用 PathMatcher
实用程序类层次结构时)使用,并在构造时解析。它与 Resource
类型本身无关。不能使用 classpath*:
前缀来构造一个实际的 Resource
,因为一个 resource 同时只指向一个资源。
Ant 风格的模式
路径位置可以包含 Ant 风格的模式,如下例所示:
/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
等),则从中获得一个 java.io.File
,并通过遍历文件系统来解析通配符。在 jar
URL 的情况下,解析器要么从中获取一个 java.net.JarURLConnection
,要么手动解析 jar
URL,然后遍历 jar
文件的内容来解析通配符。
对可移植性的影响
如果指定的路径已经是一个file
URL(隐式地因为基础 ResourceLoader
是文件系统的,或者显式地),通配符的使用保证能够以完全可移植的方式工作。
如果指定的路径是classpath
位置,解析器必须通过调用 Classloader.getResource()
来获取最后一个非通配符路径段的 URL。由于这只是路径的一个节点(而不是最终的文件),所以在 ClassLoader
的 javadoc 中实际上并没有明确定义在这种情况下返回哪种类型的 URL。实际上,它通常是一个表示目录的 java.io.File
(类路径资源解析到文件系统位置时)或某种形式的 jar URL(类路径资源解析到 jar 位置时)。尽管如此,这个操作仍然存在可移植性的担忧。
如果为最后一个非通配符段获取了一个 jar URL,解析器必须能够从中获取一个 java.net.JarURLConnection
或手动解析 jar URL,以便能够遍历 jar 的内容并解析通配符。这在大多数环境中都能正常工作,但在其它环境中会失败,强烈建议在依赖它之前,在你的特定环境中彻底测试来自 jars 的资源通配符解析。
classpath*:前缀
当构建基于 XML 的应用上下文时,位置字符串可以使用特殊的 classpath*:
前缀,如下例所示:
ApplicationContext ctx =
new ClassPathXmlApplicationContext("classpath*:conf/appContext.xml");
这个特殊的前缀指定必须获取所有与给定名称匹配的类路径资源(在内部,这实际上是通过调用 ClassLoader.getResources(…)
来完成的),然后将它们合并以形成最终的应用上下文定义。
类路径通配符依赖于底层 ClassLoader
的 getResources()
方法。由于现在大多数应用服务器都提供自己的 ClassLoader
实现,其行为可能会有所不同,特别是在处理 jar 文件时。一个简单的测试来检查 classpath*
是否有效,是使用 ClassLoader
从类路径上的 jar 中加载一个文件:getClass().getClassLoader().getResources("")
。尝试对这个测试用例进行测试,这些文件具有相同的名称但位于两个不同的位置——例如,具有相同名称和路径但在类路径上不同的 jar 中的文件。如果返回了不恰当的结果,请检查应用服务器文档以了解可能影响 ClassLoader
行为的设置。
还可以将 classpath*:
前缀与位置路径其余部分中的 PathMatcher
模式结合起来使用(例如,classpath*:META-INF/*-beans.xml
)。在这种情况下,解析策略相当简单:在最后一个非通配符路径段上使用 ClassLoader.getResources()
调用,以获取类加载器层次结构中所有匹配的资源,然后对每个资源使用前面描述的相同 PathMatcher
解析策略来处理通配符子路径。
其它与通配符相关的说明
classpath*:
与 Ant 风格模式结合使用时,只有在模式开始之前至少有一个根目录,才能可靠地工作,除非实际的目标文件驻留在文件系统中。这意味着像 classpath*:*.xml
这样的模式可能无法从 jar 文件的根目录检索文件,而只能从展开目录的根目录检索文件。
Spring 检索类路径条目的能力源自 JDK 的 ClassLoader.getResources()
方法,该方法仅在空字符串(表示要搜索的潜在根目录)的情况下返回文件系统位置。Spring 也会评估 URLClassLoader
运行时配置和 jar 文件中的 java.class.path
清单,但这不保证会导致可移植的行为。
扫描类路径包需要类路径中存在相应的目录条目。当使用 Ant 构建 JAR 时,不要激活 JAR 任务的 files-only
开关。此外,基于某些环境的安全策略,类路径目录可能不会暴露出来——例如,在 JDK 1.7.0_45 及更高版本上的独立应用程序(这需要在你的清单中设置 ‘Trusted-Library’)。
在 JDK 9 的模块路径(Jigsaw)上,Spring 的类路径扫描通常按预期工作。在这里,同样强烈建议将资源放入专用目录中,以避免前面提到的搜索 jar 文件根级别时的可移植性问题。
在classpath:
资源中使用Ant风格的模式并不保证能够找到匹配的资源,如果需要搜索的根包存在于多个类路径位置的话。请考虑以下资源位置的例子:
com/mycompany/package1/service-context.xml
现在考虑可能使用Ant风格的路径试图找到该文件:
classpath:com/mycompany/**/service-context.xml
这样的资源可能只存在于类路径中的一个位置,但是当使用前例中的路径试图解析它时,解析器会从getResource("com/mycompany")
返回的(第一个)URL开始工作。如果这个基础包节点存在于多个ClassLoader
位置,所需的资源可能并不存在于找到的第一个位置中。因此,在这种情况下,你应该优先使用classpath*:
与相同的Ant风格模式,它会搜索包含com.mycompany
基础包的所有类路径位置:classpath*:com/mycompany/**/service-context.xml
。
FileSystemResource注意事项
未附加到FileSystemApplicationContext
的FileSystemResource
(即,当FileSystemApplicationContext
不是实际的ResourceLoader
时)会按照你预期的方式处理绝对路径和相对路径。相对路径是相对于当前工作目录,而绝对路径则是相对于文件系统的根目录。
然而,由于向后兼容性(历史)原因,当FileSystemApplicationContext
是ResourceLoader
时,情况会发生变化。FileSystemApplicationContext
强制所有附加的FileSystemResource
实例将所有位置路径视为相对路径,无论它们是否以斜杠开头。实际上,这意味着以下示例是等效的:
ApplicationContext ctx =
new FileSystemXmlApplicationContext("conf/context.xml");
ApplicationContext ctx =
new FileSystemXmlApplicationContext("/conf/context.xml");
以下示例也是等效的(即使它们应该是不同的,因为一种情况是相对的,另一种是绝对的):
FileSystemXmlApplicationContext ctx = ...;
ctx.getResource("some/resource/path/myTemplate.txt");
FileSystemXmlApplicationContext ctx = ...;
ctx.getResource("/some/resource/path/myTemplate.txt");
实际上,如果你需要真正的绝对文件系统路径,应该避免使用FileSystemResource
或FileSystemXmlApplicationContext
的绝对路径,并强制使用UrlResource
,方法是使用file:
URL前缀。以下示例展示了如何操作:
// actual context type doesn't matter, the Resource will always be UrlResource
ctx.getResource("file:///some/resource/path/myTemplate.txt");
// force this FileSystemXmlApplicationContext to load its definition via a UrlResource
ApplicationContext ctx =
new FileSystemXmlApplicationContext("file:///conf/context.xml");