Spring Framework核心技术:Resources

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。

其它方法允许你获取表示资源的实际 URLFile 对象(如果底层实现兼容并支持该功能)。

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 支持解析为 FileURL

PathResource

这是针对 java.nio.file.Path 句柄的 Resource 实现,通过 Path API 执行所有操作和转换。它支持解析为 FileURL,并实现了扩展的 WritableResource 接口。PathResource 实际上是 FileSystemResource 的纯 java.nio.path.Path 基础替代品,具有不同的 createRelative 行为。

ServletContextResource

这是针对 ServletContext 资源的 Resource 实现,它在相关 Web 应用程序的根目录内解释相对路径。

它始终支持流访问和 URL 访问,但仅在 Web 应用程序存档被扩展且资源实际存在于文件系统上时才允许 java.io.File 访问。它是否被扩展并位于文件系统上,或者直接从 JAR 或其它地方(如数据库)访问,实际上取决于 Servlet 容器。

InputStreamResource

InputStreamResource 是针对给定 InputStreamResource 实现。只有在没有特定的 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。以下示例使用 filehttps 前缀:

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 接口的替代方案。传统的constructorbyType 自动装配模式能够分别为构造函数参数或 setter 方法参数提供 ResourceLoader。为了更大的灵活性(包括能够自动装配字段和多参数方法),可以考虑使用基于注解的自动装配特性。在这种情况下,只要字段、构造函数或方法带有 @Autowired 注解,ResourceLoader 就会自动装配到期望 ResourceLoader 类型的字段、构造函数参数或方法参数中。

要为包含通配符的资源路径或使用特殊的 classpath*: 资源前缀加载一个或多个 Resource 对象,请考虑将 ResourcePatternResolver 的实例自动装配到你的应用组件中,而不是 ResourceLoader

Resources 作为依赖

如果 bean 本身要通过某种动态过程确定并提供资源路径,那么让 bean 使用 ResourceLoaderResourcePatternResolver 接口来加载资源可能是有意义的。例如,考虑加载某种模板,其中所需的具体资源取决于用户的角色。如果资源是静态的,那么完全可以不用 ResourceLoader 接口(或 ResourcePatternResolver 接口),让 bean 暴露它需要的 Resource 属性,并期望它们被注入到 bean 中。

使得注入这些属性变得简单的是,所有应用上下文都注册并使用了一个特殊的 JavaBeans PropertyEditor,它可以将字符串路径转换为 Resource 对象。例如,下面的 MyBean 类有一个类型为 Resourcetemplate 属性。

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,根据应用上下文的确切类型,资源将通过 ClassPathResourceFileSystemResourceServletContextResource 加载。

如果需要强制使用特定的 Resource 类型,可以使用前缀。以下两个示例展示了如何强制使用 ClassPathResourceUrlResource(后者用于访问文件系统中的文件):

<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.xmlrepositories.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(…​) 来完成的),然后将它们合并以形成最终的应用上下文定义。

类路径通配符依赖于底层 ClassLoadergetResources() 方法。由于现在大多数应用服务器都提供自己的 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注意事项

未附加到FileSystemApplicationContextFileSystemResource(即,当FileSystemApplicationContext不是实际的ResourceLoader时)会按照你预期的方式处理绝对路径和相对路径。相对路径是相对于当前工作目录,而绝对路径则是相对于文件系统的根目录。

然而,由于向后兼容性(历史)原因,当FileSystemApplicationContextResourceLoader时,情况会发生变化。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");

实际上,如果你需要真正的绝对文件系统路径,应该避免使用FileSystemResourceFileSystemXmlApplicationContext的绝对路径,并强制使用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");
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值