本章涉及Spring如何处理资源以及如何在Spring中使用资源。它包括以下主题。
- 简介
- Resource 接口
- 内置的 Resource 实现
- ResourceLoader 接口
- ResourcePatternResolver 接口
- ResourceLoaderAware 接口
- 作为依赖的 Resources
- Application Context 和资源路径
2.1. 简介
Java的标准 java.net.URL 类和各种URL前缀的标准处理程序,不幸的是,还不足以满足对低级资源的所有访问。例如,没有标准化的 URL 实现可用于访问需要从classpath或相对于 ServletContext 获得的资源。虽然有可能为专门的 URL 前缀注册新的处理程序(类似于现有的 http: 等前缀的处理程序),但这通常是相当复杂的,而且 URL 接口仍然缺乏一些理想的功能,例如检查被指向的资源是否存在的方法。
2.2.Resource接口
位于 org.springframework.core.io. 包中的Spring Resource 接口,旨在成为一个更有能力的接口,用于抽象访问低级资源。下面的列表提供了 Resource 接口的概述。请参阅 Resource javadoc以了解更多细节。
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,该字符串以未经修饰或简单的形式被用来创建适合该上下文实现的 Resource,或者通过 String 路径上的特殊前缀,让调用者指定必须创建和使用一个特定的 Resource 实现。
虽然 Resource 接口在Spring中被大量使用,但在你自己的代码中,它作为一个普通的实用类,用于访问资源,即使你的代码不知道或不关心Spring的任何其他部分,它实际上也非常方便。虽然这将你的代码与Spring联系在一起,但它实际上只是与这一小部分实用类联系在一起,作为 URL 的一个更有能力的替代品,可以被认为等同于你用于此目的的任何其他库。
Resource 抽象并不取代功能。它尽可能地包装它。例如,UrlResource 包装了一个 URL,并使用被包装的 URL 来完成其工作。 |
2.3. 内置的Resource实现
Spring包括几个内置的 Resource 实现。
- UrlResource
- ClassPathResource
- FileSystemResource
- PathResource
- ServletContextResource
- InputStreamResource
- ByteArrayResource
关于Spring中可用的 Resource 实现的完整列表,请查阅 Resource avadoc中的 "所有已知的实现类" 部分。
2.3.1.UrlResource
UrlResource 包装了一个 java.net.URL,可以用来访问任何通常可以用URL访问的对象,如文件、HTTPS目标、FTP目标等。所有的URL都有一个标准化的 String 表示,这样,适当的标准化前缀被用来表示一个URL类型与另一个URL类型。这包括 file: 用于访问文件系统路径,https: 用于通过HTTPS协议访问资源,ftp: 用于通过FTP访问资源,以及其他。
UrlResource 是由Java代码通过明确使用 UrlResource 构造函数来创建的,但当你调用一个API方法时,往往是隐式创建的,该方法需要一个代表路径的 String 参数。对于后一种情况,JavaBeans 的 PropertyEditor 最终决定创建哪种类型的 Resource。如果路径字符串包含一个众所周知的(对属性编辑器来说)前缀(如 classpath:),它将为该前缀创建一个适当的专用 Resource。然而,如果它不认识这个前缀,它就假定这个字符串是一个标准的URL字符串,并创建一个 UrlResource。
2.3.2.ClassPathResource
该类表示应从 classpath 获得的资源。它使用线程上下文的类加载器、一个给定的类加载器或一个给定的类来加载资源。
如果 class path 资源驻留在文件系统中,该 Resource 实现支持作为 java.io.File 的解析,但对于驻留在 jar 中且未被扩展(由 servlet 引擎或任何环境)到文件系统中的 class path 资源,则不支持。为了解决这个问题,各种 Resource 实现总是支持解析为 java.net.URL。
Java代码通过明确使用 ClassPathResource 构造函数来创建 ClassPathResource,但当你调用一个API方法时,往往会隐含地创建,该方法需要一个代表路径的 String 参数。对于后一种情况,JavaBeans PropertyEditor 会识别字符串路径上的特殊前缀 classpath:,并在这种情况下创建一个 ClassPathResource。
2.3.3.FileSystemResource
这是一个用于 java.io.File 句柄 的 Resource 实现。它也支持 java.nio.file.Path 句柄,应用Spring标准的基于String的路径转换,但通过 java.nio.file.Files API执行所有操作。对于纯粹的基于 java.nio.path.Path 的支持,请使用 PathResource 代替。FileSystemResource 支持以`File` 和 URL 的形式解析。
2.3.4.PathResource
这是一个用于 java.nio.file.Path 处理的 Resource 实现,通过 Path API执行所有操作和转换。它支持作为 File 和 URL 的解析,也实现了扩展的 WritableResource 接口。PathResource 实际上是一个纯粹的基于 java.nio.path.Path 的、具有不同 createRelative 行为的 FileSystemResource 替代品。
2.3.5.ServletContextResource
这是一个用于ServletContext资源的 Resource 实现,它解释了相对于Web应用根目录中的相对路径。
它总是支持流访问和URL访问,但只有当Web应用程序归档文件被扩展并且资源在文件系统上时才允许 java.io.File 访问。无论它是否被扩展并在文件系统上,还是直接从JAR或其他地方(如数据库)访问(这是可以想象的),实际上都取决于Servlet容器。
2.3.6.InputStreamResource
InputStreamResource 是给定的 InputStream 的一个 Resource 实现。只有在没有特定的 Resource 实现的情况下才应该使用它。特别是在可能的情况下,最好选择 ByteArrayResource 或任何基于文件的 Resource 实现。
与其他 Resource 实现不同,这是一个已经打开的资源的描述符。因此,它从 isOpen() 返回 true。如果你需要把资源描述符保存在某个地方,或者需要多次读取一个流,请不要使用它。
2.3.7.ByteArrayResource
这是一个给定字节数组的 Resource 实现。它为给定的字节数组创建一个 ByteArrayInputStream。
它对于从任何给定的字节数组中加载内容是很有用的,而不必求助于单一用途的 InputStreamResource。
2.4.ResourceLoader接口
ResourceLoader 接口的目的是由可以返回(也就是加载)资源实例的对象来实现。下面的列表显示了 ResourceLoader 接口的定义。
public interface ResourceLoader { Resource getResource(String location); ClassLoader getClassLoader(); }
所有的应用 application context 都实现了 ResourceLoader 接口。因此,所有的 application context 都可以被用来获取 Resource 实例。
当你在一个特定的 application context 上调用 getResource(),并且指定的位置路径没有特定的前缀,你会得到一个适合该特定 application context 的 Resource 类型。例如,假设下面这段代码是针对 ClassPathXmlApplicationContext 实例运行的。
Java
Resource template = ctx.getResource("some/resource/path/myTemplate.txt");
ntext,该代码返回 ClassPathResource。如果针对 FileSystemXmlApplicationContext 实例运行相同的方法,则会返回 FileSystemResource。对于 WebApplicationContext,它将返回一个 ServletContextResource。同样地,它将为每个 context 返回适当的对象。
因此,你可以以适合于特定 application context 的方式加载资源。
另一方面,你也可以通过指定特殊的 classpath: 前缀来强制使用 ClassPathResource,而不管 application context 类型如何,正如下面的例子所示。
Java
Resource template = ctx.getResource("classpath:some/resource/path/myTemplate.txt");
过指定任何一个标准的 java.net.URL 前缀来强制使用 UrlResource。下面的例子使用了 file 和 https 的前缀。
Java
Resource template = ctx.getResource("file:///some/resource/path/myTemplate.txt"); esource template = ctx.getResource("https://myhost.com/resource/path/myTemplate.txt");
略。
Table 10. 资源字符串 |
||
前缀 |
示例 |
说明 |
classpath: |
classpath:com/myapp/config.xml |
从classpath加载。 |
file: |
file:///data/config.xml |
作为 URL 从文件系统加载。另请参见FileSystemResource 注意事项. |
https: |
https://myserver/logo.png |
以 URL 形式加载。 |
(none) |
/data/config.xml |
取决于底层的 `ApplicationContext'。 |
2.5.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文件或类路径中的不同目录可以包含具有相同路径和相同名称的多个文件。关于 classpath*: 资源前缀的通配符支持的进一步详情,请参见 Application Context 构造器资源路径中的通配符 及其子章节。
传入的 ResourceLoader(例如,通过 ResourceLoaderAware 语义提供的资源加载器)可以被检查它是否也实现了这个扩展接口。
PathMatchingResourcePatternResolver 是一个独立的实现,可以在 ApplicationContext 之外使用,也可以被 ResourceArrayPropertyEditor 用于填充 Resource[] bean属性。PathMatchingResourcePatternResolver 能够将指定的资源位置路径解析为一个或多个匹配的 Resource 对象。源路径可以是一个简单的路径,它与目标 Resource 有一对一的映射,或者可以包含特殊的 classpath*: 前缀和/或内部Ant风格的正则表达式(使用 Spring 的 org.springframework.util.AntPathMatcher 工具匹配)。后者都是有效的通配符。
任何标准 ApplicationContext 中的默认 ResourceLoader 实际上是 PathMatchingResourcePatternResolver 的一个实例,它实现了 ResourcePatternResolver 接口。ApplicationContext 实例本身也是如此,它也实现了 ResourcePatternResolver 接口并委托给默认的 PathMatchingResourcePatternResolver。 |
2.6.ResourceLoaderAware接口
ResourceLoaderAware 接口是一个特殊的回调接口,用于识别期望被提供 ResourceLoader 引用的组件。下面的列表显示了 ResourceLoaderAware 接口的定义。
public interface ResourceLoaderAware { void setResourceLoader(ResourceLoader resourceLoader); }
当一个类实现了 ResourceLoaderAware 并被部署到 application context 中时(作为Spring管理的Bean),它被 application context 识别为 ResourceLoaderAware。应用application context然后调用 setResourceLoader(ResourceLoader),将自己作为参数(请记住,Spring的所有application context都实现了 ResourceLoader 接口)。
由于 ApplicationContext 是一个 ResourceLoader,Bean也可以实现 ApplicationContextAware 接口并直接使用所提供的application context来加载资源。然而,一般来说,如果你只需要使用专门的 ResourceLoader 接口,那会更好。代码将只与资源加载接口(可被视为一个实用接口)耦合,而不是与整个Spring ApplicationContext 接口耦合。
在应用程序组件中,你也可以依赖 ResourceLoader 的自动装配,作为实现 ResourceLoaderAware 接口的替代方案。传统的 constructor 和 byType 自动装配模式(如 注入协作者(Autowiring Collaborators) 中所述)能够分别为构造器参数或设置器方法参数提供一个 ResourceLoader。为了获得更多的灵活性(包括自动装配字段和多个参数方法的能力),可以考虑使用基于注解的自动装配功能。在这种情况下,只要字段、构造函数或方法带有 @Autowired 注解,ResourceLoader 就会被自动装配到期望有 ResourceLoader 类型的字段、构造函数参数或方法参数中。更多信息请参见 使用 @Autowired。
要为包含通配符或使用特殊 classpath*: 资源前缀的资源路径加载一个或多个 Resource 对象,请考虑将 ResourcePatternResolver 的实例自动装配到你的应用程序组件中,而不是 ResourceLoader。 |
2.7. 作为依赖的 Resources
如果Bean本身要通过某种动态过程来确定和提供资源路径,那么Bean使用 ResourceLoader 或 ResourcePatternResolver 接口来加载资源可能是有意义的。例如,考虑加载某种模板,其中需要的特定资源取决于用户的角色。如果资源是静态的,完全不使用 ResourceLoader 接口(或 ResourcePatternResolver 接口)是有意义的,让Bean暴露它所需要的 Resource 属性,并期望它们被注入其中。
然后注入这些属性的琐碎之处在于,所有的应用 application context 都注册并使用一个特殊的JavaBeans PropertyEditor,它可以将 String 路径转换为 Resource 对象。例如,下面的 MyBean 类有一个 Resource 类型的 template 属性。
Java
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>
请注意,资源路径没有前缀。因此,由于application context本身将被用作 ResourceLoader,所以资源将通过 ClassPathResource、 FileSystemResource 或 ServletContextResource 加载,这取决于 application context 的具体类型。
如果你需要强制使用一个特定的 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 的key下—例如,在一个提供给Spring Environment 的属性文件中(见 Environment 抽象)。然后,模板路径可以通过 @Value 注解用属性占位符来引用(见 使用 @Value)。Spring将以字符串的形式检索模板路径的值,一个特殊的 PropertyEditor 将把字符串转换为 Resource 对象,并注入 MyBean 构造函数中。下面的例子演示了如何实现这一点。
Java
@Component public class MyBean { private final Resource template; public MyBean(@Value("${template.path}") Resource template) { this.template = template; } // ... }
如果我们想支持在 classpath 的多个位置—例如在classpath的多个jars中—的同一路径下发现的多个template,我们可以使用特殊的 classpath*: 前缀和通配符来定义 templates.path key 为 classpath*:/config/templates/*.txt。如果我们重新定义 MyBean 类如下,Spring将把 template path pattern 转换为一个 Resource 对象数组,可以注入 MyBean 构造函数中。
Java
@Component public class MyBean { private final Resource[] templates; public MyBean(@Value("${templates.path}") Resource[] templates) { this.templates = templates; } // ... }
2.8. Application Context 和资源路径
本节介绍了如何用资源创建应用 application context,包括与XML一起使用的快捷方式,如何使用通配符,以及其他细节。
2.8.1. 构建 Application Context
application context 构造函数(对于一个特定的 application context 类型)通常需要一个字符串或字符串数组作为资源的位置路径,例如构成 context 定义的XML文件。
当这样的位置路径没有前缀时,从该路径建立并用于加载Bean定义的特定 Resource 类型取决于并适合于特定的应用环境。例如,考虑下面的例子,它创建了一个 ClassPathXmlApplicationContext。
Java
ApplicationContext ctx = new ClassPathXmlApplicationContext("conf/appContext.xml");
由于使用了 ClassPathResource,所以 bean 定义是从 classpath 中加载的。但是,请看下面这个例子,它创建了一个 FileSystemXmlApplicationContext。
Java
ApplicationContext ctx = new FileSystemXmlApplicationContext("conf/appContext.xml");
现在,Bean的定义是从文件系统的一个位置(在这种情况下,相对于当前工作目录)加载的。
请注意,在位置路径上使用特殊的 classpath 前缀或标准的URL前缀会覆盖为加载Bean定义而创建的 Resource 的默认类型。考虑一下下面的例子。
Java
ApplicationContext ctx = new FileSystemXmlApplicationContext("classpath:conf/appContext.xml");
使用 FileSystemXmlApplicationContext 会从 classpath 中加载 Bean 定义。但是,它仍然是一个 FileSystemXmlApplicationContext。如果它随后被用作 ResourceLoader,任何未加前缀的路径仍被视为文件系统路径。
构建ClassPathXmlApplicationContext实例 - 快捷方式
ClassPathXmlApplicationContext 公开了一些构造函数,以方便实例化。基本的想法是,你可以只提供一个字符串数组,其中只包含XML文件本身的文件名(没有领先的路径信息),同时提供一个 Class。然后 ClassPathXmlApplicationContext 从提供的类中导出路径信息。
考虑以下目录布局。
com/ example/ services.xml repositories.xml MessengerService.class
下面的例子显示了如何实例化一个 ClassPathXmlApplicationContext 实例,该实例由名为 services.xml 和 repositories.xml 的文件(在classpath上)中定义的bean组成。
Java
ApplicationContext ctx = new ClassPathXmlApplicationContext( new String[] {"services.xml", "repositories.xml"}, MessengerService.class);
有关各种构造函数的详细信息,请参见 ClassPathXmlApplicationContext javadoc。
2.8.2. Application Context 构造器资源路径中的通配符
application context 构造函数值中的资源路径可以是简单的路径(如前所示),每个路径都有一个与目标 Resource 的一对一映射,或者,可以包含特殊的 classpath*: 前缀或内部Ant风格的模式(通过使用Spring的 PathMatcher 工具进行匹配)。后者都是有效的通配符。
这种机制的一个用途是当你需要进行组件式的应用组装时。所有的组件都可以将上下文定义片段发布到一个众所周知的位置路径上,并且,当最终的应用程序上下文使用相同的路径创建时,前缀为 classpath*:,所有的组件片段都会被自动接收。
请注意,这种通配符是专门针对在application context构造器中使用资源路径的(或者当你直接使用 PathMatcher 实用类层次结构时),并在构造时解析。它与 Resource 类型本身没有关系。你不能使用 classpath*: 前缀来构造一个实际的 Resource,一个 Resources 对象一次只指向一个资源。
Ant 风格的 Pattern
路径(Path )位置可以包含Ant风格的pattern,如下面的例子所示。
/WEB-INF/*-context.xml com/mycompany/**/applicationContext.xml file:C:/some/path/*-context.xml classpath:com/mycompany/**/applicationContext.xml
当路径位置包含一个Ant风格的pattern时,解析器遵循一个更复杂的程序来尝试解析通配符。它为路径产生一个 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(在classpath资源解析到文件系统位置的情况下)或某种jar URL(在classpath资源解析到jar位置的情况下)。不过,在这个操作上还是有一个可移植性问题。
如果为最后一个非通配符段获得了一个 jar URL,解析器必须能够从中获得 java.net.JarURLConnection 或手动解析 jar URL,以便能够浏览 jar 的内容并解析通配符。这在大多数环境中确实有效,但在其他环境中却失败了,我们强烈建议在你依赖它之前,在你的特定环境中对来自jar的资源的通配符解析进行彻底测试。
classpath*:前缀
在构建基于XML的应用程序上下文时,位置字符串可以使用特殊的 classpath*: 前缀,如下例所示。
Java
ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath*:conf/appContext.xml");
这个特殊的前缀指定了所有符合给定名称的classpath资源必须被获取(在内部,这基本上是通过调用 ClassLoader.getResources(…) 发生的),然后合并以形成最终的 application context 定义。
通配符classpath依赖于底层 ClassLoader 的 getResources() 方法。由于现在大多数应用服务器都提供自己的 ClassLoader 实现,行为可能会有所不同,特别是在处理jar文件时。检查 classpath* 是否有效的一个简单测试是使用 ClassLoader 从 classpath 上的jar中加载一个文件:getClass().getClassLoader().getResources("<someFileInsideTheJar>")。试着用具有相同名称但位于两个不同位置的文件进行这个测试—例如,具有相同名称和相同路径但位于classpath上不同jar中的文件。如果返回的结果不合适,请检查应用服务器文档中可能影响 ClassLoader 行为的设置。 |
你也可以将 classpath*: 前缀与位置路径其余部分的 PathMatcher pattern相结合(例如,classpath*:META-INF/*-beans.xml)。在这种情况下,解析策略是相当简单的。在最后一个非通配符路径段上使用 ClassLoader.getResources() 调用,以获得类加载器层次结构中的所有匹配资源,然后在每个资源上,使用前面描述的通配符子路径的相同 PathMatcher 解析策略。
与通配符有关的其他说明
注意,classpath*:,当与Ant风格的pattern相结合时,只有在pattern开始前至少有一个根目录时才能可靠地工作,除非实际的目标文件位于文件系统中。这意味着像 classpath*:*.xml 这样的pattern可能不会从jar文件的根目录中检索文件,而只能从扩展目录的根目录中检索。
Spring 检索 classpath 条目的能力源于JDK的 ClassLoader.getResources() 方法,它只返回空字符串的文件系统位置(表示要搜索的潜在root)。Spring也会评估 URLClassLoader 的运行时配置和 java.class.path 清单,但这并不能保证导致可移植行为。
扫描classpath包需要classpath中存在相应的目录条目。当你用Ant构建JAR时,不要激活JAR任务的 files-only 开关。另外,在某些环境中,classpath目录可能不会根据安全策略被暴露出来—例如,JDK 1.7.0_45及以上版本的独立应用程序(这需要在清单中设置 'Trusted-Library'。见 https://stackoverflow.com/questions/19394570/java-jre-7u45-breaks-classloader-getresources )。 在JDK 9的模块路径(Jigsaw)上,Spring的classpath扫描一般都能如期进行。这里也强烈建议将资源放到一个专门的目录中,以避免前面提到的搜索jar文件根层的可移植性问题。 |
含有 classpath: 资源的Ant风格的pattern不保证能找到匹配的的资源,如果要搜索的root包在多个classpath位置上可用。考虑到下面这个资源位置的例子。
com/mycompany/package1/service-context.xml
现在考虑一个Ant风格的path,有人可能会用它来试图找到这个文件。
classpath:com/mycompany/**/service-context.xml
这样的资源可能只存在于classpath中的一个位置,但是当像前面的例子那样的路径被用来试图解析它时,解析器根据 getResource("com/mycompany"); 返回的(第一个)URL来工作。如果这个基础包节点存在于多个 ClassLoader 位置,所需的资源可能不存在于找到的第一个位置。因此,在这种情况下,你应该更倾向于使用 classpath*: 与Ant风格相同的pattern,它可以搜索所有包含 com.mycompany 基础包的 classpath 位置:classpath*:com/mycompany/**/service-context.xml。
2.8.3.FileSystemResource注意事项
未附加到 FileSystemApplicationContext 的 FileSystemResource(也就是说,当 FileSystemApplicationContext 不是实际的 ResourceLoader 时)会按照您的预期处理绝对和相对路径。相对路径是指相对于当前工作目录,而绝对路径是指相对于文件系统的root。
然而,出于向后兼容(历史)的原因,当 FileSystemApplicationContext 为 ResourceLoader 时,情况会发生变化。FileSystemApplicationContext 强制所有附加的 FileSystemResource 实例将所有位置路径视为相对路径,无论它们是否以前导斜线开始。在实践中,这意味着以下例子是等同的。
Java
ApplicationContext ctx = new FileSystemXmlApplicationContext("conf/context.xml");
Java
ApplicationContext ctx = new FileSystemXmlApplicationContext("/conf/context.xml");
下面的例子也是等价的(尽管它们的不同是有道理的,因为一种情况是相对的,另一种是绝对的)。
Java
FileSystemXmlApplicationContext ctx = ...; ctx.getResource("some/resource/path/myTemplate.txt");
Java
FileSystemXmlApplicationContext ctx = ...; ctx.getResource("/some/resource/path/myTemplate.txt");
在实践中,如果需要真正的绝对文件系统路径,应避免使用 FileSystemResource 或 FileSystemXmlApplicationContext 的绝对路径,而是通过使用 file: URL 前缀强制使用 UrlResource。下面的例子展示了如何做到这一点。
Java
// actual context type doesn't matter, the Resource will always be UrlResource ctx.getResource("file:///some/resource/path/myTemplate.txt");
Java
// force this FileSystemXmlApplicationContext to load its definition via a UrlResource ApplicationContext ctx = new FileSystemXmlApplicationContext("file:///conf/context.xml");
官网:Doker 多克; 官方旗舰店:首页-Doker 多克 多克创新科技企业店-淘宝网 技术人的数码品牌!!!全品优惠,期待您的支持!!!