文章摘要(AI生成)
2. Resources本章介绍 Spring 如何处理资源以及如何在 Spring 中使用资源。它包括以下主题:介绍Resource界面内置Resource实现ResourceLoader界面ResourcePatternResolver界面ResourceLoaderAware界面资源作为依赖应
2. Resources
本章介绍 Spring 如何处理资源以及如何在 Spring 中使用资源。它包括以下主题:
- 介绍
Resource
界面- 内置
Resource
实现 ResourceLoader
界面ResourcePatternResolver
界面ResourceLoaderAware
界面- 资源作为依赖
- 应用程序上下文和资源路径
2.1. 介绍
不幸的是,Java 的标准 java.net.URL
类和各种 URL
前缀的标准处理程序不足以满足对低级资源的所有访问。例如,没有可用于访问需要从类路径或相对于 ServletContext
获取的资源的标准化URL
实现。虽然可以为专门的 URL 前缀注册新的处理程序(类似于http:
等前缀的现有处理程序),但这通常相当复杂,并且 URL 接口仍然缺乏一些理想的功能,例如检查是否存在的方法所指向的资源的名称。
2.2. Resource
接口
位于org.springframework.core.io.
包中的SpringResource
接口旨在成为一个更强大的接口,用于抽象对低级资源的访问。以下清单提供了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
不能多次读取,必须只读取一次然后关闭以避免资源泄漏。对于所有常用资源实现返回false
(InputStreamResource
除外)。getDescription()
:返回此资源的描述,用于在使用该资源时输出错误。这通常是完全限定的文件名或资源的实际 URL。
其他方法让您获得表示资源的实际URL
或File
对象(如果底层实现兼容并支持该功能)。
Resource
接口的一些实现还为支持写入的资源实现了扩展 WritableResource
接口。
Spring 本身广泛使用Resource
抽象,在需要资源时作为许多方法签名中的参数类型。某些 Spring API 中的其他方法(例如各种 ApplicationContext
实现的构造函数)采用 String
,该 String
以原始或简单的形式用于创建适合该上下文实现的资源,或者通过 String
路径上的特殊前缀,让调用者指定必须创建和使用特定的资源实现。
虽然Resource
接口在 Spring 和 Spring 中被大量使用,但实际上在您自己的代码中将其本身用作通用实用程序类非常方便,用于访问资源,即使您的代码不知道或不关心spring任何其他部分。虽然这会将您的代码与 Spring 耦合,但它实际上只将它耦合到这一小部分实用程序类,它可以作为更强大的替代品,URL
并且可以被认为等同于您将用于此目的的任何其他库。
Resource
抽象不会取代功能。它尽可能地包装它。例如,UrlResource 包装 URL 并使用包装的 URL 来完成其工作。
2.3. 内置Resource
实现
Spring 包括几个内置的Resource
实现:
UrlResource
ClassPathResource
FileSystemResource
PathResource
ServletContextResource
InputStreamResource
ByteArrayResource
有关 Spring Resource
中可用实现的完整列表,请参阅javadoc Resource
的“所有已知的实现类”部分 。
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
表示路径的参数。对于后一种情况,JavaBeansPropertyEditor
最终决定创建哪种类型Resource
。如果路径字符串包含一个众所周知的(对属性编辑器而言)前缀(例如classpath:
),它会为该前缀创建一个适当的专用化Resource
。但是,如果它不能识别前缀,它会假定该字符串是标准 URL 字符串并创建一个UrlResource
.
2.3.2. ClassPathResource
此类表示应从类路径获取的资源。它使用线程上下文类加载器、给定的类加载器或给定的类来加载资源。
如果类路径资源驻留在文件系统中,则此资源实现支持解析为 java.io.File
,但不支持驻留在 jar 中且尚未(通过 servlet 引擎或任何环境)扩展到文件系统。为了解决这个问题,各种 Resource
实现始终支持解析为 java.net.URL
。
ClassPathResource
是由 Java 代码通过显式使用ClassPathResource
构造函数创建的,但通常是在调用 API 方法时隐式创建的,该方法采用 String
表示路径的参数。对于后一种情况,JavaBeans PropertyEditor
识别字符串路径上的特殊前缀 ,classpath:
,并在这种情况下创建 ClassPathResource
。
2.3.3. FileSystemResource
这是java.io.File
句柄的Resource
实现。它还支持 java.nio.file.Path
句柄,应用 Spring 的标准基于字符串的路径转换,但通过java.nio.file.Files
API 执行所有操作。对于纯 java.nio.path.Path
基于支持,请改用 PathResource
。FileSystemResource
支持解析为File
和 URL
。
2.3.4. PathResource
这是句柄的Resource
实现,通过API 执行所有操作和转换。它支持解析为 a和 as a并且还实现了扩展接口。 实际上是具有不同行为的纯基于替代方案。java.nio.file.Path``Path``File``URL``WritableResource``PathResource``java.nio.path.Path``FileSystemResource``createRelative
2.3.5. ServletContextResource
这是ServletContext
资源的 Resource
实现,它解释相关 Web 应用程序根目录中的相对路径。
它始终支持流访问和 URL 访问,但仅在扩展 Web 应用程序存档且资源物理位于文件系统上时才允许java.io.File
访问。它是否被扩展并在文件系统上或直接从 JAR 或其他地方(如数据库)访问(这是可以想象的)实际上取决于 Servlet 容器。
2.3.6. InputStreamResource
InputStreamResource
是Resource
给定InputStream
的实现。只有在没有特定Resource
实现适用时才应使用它。特别是,在可能的情况下,首选ByteArrayResource
或任何基于文件的Resource
实现。
与其他Resource
实现相比,这是一个已打开资源的描述符。因此,它isOpen()
方法返回true
。 如果您需要将资源描述符保存在某处或需要多次读取流,请不要使用它。
2.3.7. ByteArrayResource
这是Resource
给定字节数组的实现。它为给定的字节数组创建一个 ByteArrayInputStream
。
它对于从任何给定的字节数组加载内容很有用,而不必求助于单次使用InputStreamResource
。
2.4. 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
对象的策略:
前缀 | 例子 | 解释 |
---|---|---|
classpath: | classpath:com/myapp/config.xml |
从类路径加载。 |
file: | file:///data/config.xml |
从文件系统加载为 URL 。另请参阅FileSystemResource 注意事项。 |
https: | https://myserver/logo.png |
加载为URL . |
无 | /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*:
通配符支持的更多详细信息,请参阅应用程序上下文构造函数资源路径中的通配符及其小节。
可以检查传入的ResourceLoader
(例如,通过 ResourceLoaderAware
语义提供的)是否也实现了此扩展接口。
PathMatchingResourcePatternResolver
是一个独立的实现,可以在ApplicationContext
外部使用,并且也可以被 ResourceArrayPropertyEditor
用于填充 Resource[]
bean 属性。 PathMatchingResourcePatternResolver
能够将指定的资源位置路径解析为一个或多个匹配的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
并部署到应用程序上下文(作为 Spring 管理的 bean)中时,它被应用程序上下文识别为ResourceLoaderAware
。然后应用程序上下文调用setResourceLoader(ResourceLoader)
,将自己作为参数提供(请记住,Spring 中的所有应用程序上下文都实现了该ResourceLoader
接口)。
由于 ApplicationContext
是一个 ResourceLoader
,因此 bean 也可以实现 ApplicationContextAware
接口并直接使用提供的应用程序上下文来加载资源。但是,一般来说,如果您只需要专用接口,最好使用ResourceLoader
专用接口。该代码将仅与资源加载接口(可以认为是实用程序接口)耦合,而不与整个 Spring ApplicationContext
接口耦合。
在应用程序组件中,您还可以依赖 ResourceLoader
的自动装配作为实现ResourceLoaderAware
接口的替代方法。传统的构造函数和 byType 自动装配模式(如自动装配协作者中所述)能够分别为构造函数参数或 setter 方法参数提供 ResourceLoader
。为了获得更大的灵活性(包括自动装配字段和多个参数方法的能力),请考虑使用基于注解的自动装配功能。在这种情况下,只要相关字段、构造函数或方法带有 @Autowired
注解,ResourceLoader
就会自动装配到需要 ResourceLoader
类型的字段、构造函数参数或方法参数中。有关更多信息,请参阅使用@Autowired。
要为包含通配符或使用特殊classpath*:
资源前缀的资源路径加载一个或多个 Resource 对象,请考虑将 ResourcePatternResolver
实例(而不是 ResourceLoader)自动装配到应用程序组件中。
2.7. 资源作为依赖
如果 bean 本身要通过某种动态过程确定并提供资源路径,则 bean 使用 ResourceLoader
或ResourcePatternResolver
接口来加载资源可能是有意义的。例如,考虑加载某种模板,其中所需的特定资源取决于用户的角色。如果资源是静态的,则完全消除ResourceLoader
接口(或 ResourcePatternResolver
接口)的使用是有意义的,让 bean 公开其所需的 Resource 属性,并期望将它们注入其中。
然后注入这些属性变得微不足道的是,所有应用程序上下文都注册并使用一个特殊的 JavaBeans PropertyEditor
,它可以将String
路径转换为Resource
对象。例如,以下MyBean
类具有Resource
类型的template
属性。
package example;
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
引用模板路径(请参阅使用@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;
}
// ...
}
2.8. 应用程序上下文和资源路径
本节介绍如何使用资源创建应用程序上下文,包括使用 XML 的快捷方式、如何使用通配符以及其他详细信息。
2.8.1. 构建应用程序上下文
应用程序上下文构造函数(针对特定应用程序上下文类型)通常采用字符串或字符串数组作为资源的位置路径,例如构成上下文定义的 XML 文件。
当这样的位置路径没有前缀时,Resource
从该路径构建并用于加载 bean 定义的特定类型取决于并适用于特定的应用程序上下文。例如,考虑以下示例,该示例创建一个 ClassPathXmlApplicationContext
:
ApplicationContext ctx = new ClassPathXmlApplicationContext("conf/appContext.xml");
bean 定义是从类路径加载的,因为使用了ClassPathResource
。但是,请考虑以下示例,该示例创建一个FileSystemXmlApplicationContext
:
ApplicationContext ctx =
new FileSystemXmlApplicationContext("conf/appContext.xml");
现在 bean 定义从文件系统位置加载(在这种情况下,相对于当前工作目录)。
请注意,在位置路径上使用特殊的类路径前缀或标准 URL 前缀会覆盖为加载 bean 定义而创建的默认资源类型。考虑以下示例:
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
以下示例显示了如何实例化由名为services.xml
和 repositories.xml
(位于类路径上)的文件中定义的 bean 组成的 ClassPathXmlApplicationContext
实例:
ApplicationContext ctx = new ClassPathXmlApplicationContext(
new String[] {"services.xml", "repositories.xml"}, MessengerService.class);
有关各种构造函数的详细信息,请参阅ClassPathXmlApplicationContext
javadoc。
2.8.2. 应用程序上下文构造函数资源路径中的通配符
应用程序上下文构造函数值中的资源路径可能是简单路径(如前所示),每个路径都具有到目标Resource
的一对一映射,或者,可能包含特殊classpath*:
前缀或内部 Ant 样式模式(匹配使用 Spring 的PathMatcher
实用程序)。后者都是有效的通配符。
这种机制的一个用途是当您需要进行组件式应用程序组装时。所有组件都可以将上下文定义片段发布到一个众所周知的位置路径,并且,当最终应用程序上下文使用以 classpath*:
为前缀的相同路径创建时 ,所有组件片段都会被自动拾取。
请注意,此通配符特定于应用程序上下文构造函数中资源路径的使用(或当您PathMatcher
直接使用实用程序类层次结构时),并在构造时解析。Resource
它与类型本身无关。您不能使用classpath*:
前缀来构造实际的Resource
,因为资源一次仅指向一个资源。
Ant样式的模式
路径位置可以包含 Ant 样式的模式,如以下示例所示:
/WEB-INF/*-context.xml
com/mycompany/**/applicationContext.xml
file:C:/some/path/*-context.xml
classpath:com/mycompany/**/applicationContext.xml
当路径位置包含 Ant 样式模式时,解析器会遵循更复杂的过程来尝试解析通配符。它为直到最后一个非通配符段的路径生成一个资源,并从中获取一个 URL。如果此 URL 不是jar:
URL 或特定于容器的变体(例如 WebLogic 中的 zip:
、WebSphere 中的 wsjar
等),则会从中获取 java.io.File
并用于通过遍历来解析通配符文件系统。对于 jar URL,解析器要么从中获取 java.net.JarURLConnection
,要么手动解析 jar URL,然后遍历 jar 文件的内容来解析通配符。
对可移植性的影响
如果指定的路径已经是一个文件 URL(无论是隐式的,因为基本ResourceLoader
是一个文件系统,还是显式的),通配符保证以完全可移植的方式工作。
如果指定路径是位置,则解析器必须通过调用classpath
获取最后一个非通配符路径段 URL 。Classloader.getResource()
由于这只是路径的一个节点(不是末尾的文件),因此实际上未定义(在 ClassLoader
javadoc 中)在这种情况下返回的 URL 类型。在实践中,它始终是java.io.File
表示目录(类路径资源解析为文件系统位置的位置)或某种 jar URL(类路径资源解析为 jar 位置的位置)。尽管如此,此操作仍存在可移植性问题。
如果为最后一个非通配符段获取 jar URL,则解析器必须能够从中获取一个java.net.JarURLConnection
或手动解析 jar URL,以便能够遍历 jar 的内容并解析通配符。这在大多数环境中都有效,但在其他环境中失败,我们强烈建议在您依赖它之前,在您的特定环境中彻底测试来自 jar 的资源的通配符解析。
classpath*:
前缀
在构建基于 XML 的应用程序上下文时,位置字符串可能会使用特殊classpath*:
前缀,如以下示例所示:
ApplicationContext ctx =
new ClassPathXmlApplicationContext("classpath*:conf/appContext.xml");
这个特殊的前缀指定必须获取与给定名称匹配的所有类路径资源(在内部,这基本上是通过对ClassLoader.getResources(…)
的调用发生的 ),然后合并以形成最终的应用程序上下文定义。
通配符类路径依赖于底层 ClassLoader 的 getResources() 方法。由于现在大多数应用程序服务器都提供自己的 ClassLoader 实现,因此行为可能会有所不同,尤其是在处理 jar 文件时。检查 classpath* 是否有效的一个简单测试是使用 ClassLoader 从类路径上的 jar 中加载文件: getClass().getClassLoader().getResources(“”)。尝试使用具有相同名称但驻留在两个不同位置的文件进行此测试 - 例如,具有相同名称和相同路径但位于类路径上不同 jar 中的文件。如果返回不适当的结果,请检查应用程序服务器文档以了解可能影响类加载器行为的设置。
您还可以将classpath*:
前缀与PathMatcher
位置路径的其余部分中的模式结合起来(例如,classpath*:META-INF/*-beans.xml
)。在这种情况下,解析策略相当简单:在最后一个非通配符路径段上使用调用ClassLoader.getResources()
以获取类加载器层次结构中的所有匹配资源,然后,在每个资源上,PathMatcher
使用前面描述的相同解析策略通配符子路径。
与通配符有关的其他说明
请注意classpath*:
,当与 Ant 样式模式结合使用时,仅在模式开始之前至少与一个根目录可靠地工作,除非实际的目标文件驻留在文件系统中。这意味着诸如classpath*:*.xml
类的模式可能不会从 jar 文件的根目录中检索文件,而只能从扩展目录的根目录中检索文件。
Spring 检索类路径条目的能力源自 JDK 的 ClassLoader.getResources()
方法,该方法仅返回空字符串的文件系统位置(指示要搜索的潜在根)。Spring 也会评估 URLClassLoader
运行时配置和java.class.path
jar 文件中的清单,但这并不保证会导致可移植行为。
类路径包的扫描需要类路径中存在相应的目录条目。使用 Ant 构建 JAR 时,不要激活 JAR 任务的files-only
开关。此外,根据某些环境中的安全策略,类路径目录可能不会暴露——例如,JDK 1.7.0_45 及更高版本上的独立应用程序(这需要在清单中设置“可信库”。请参阅 https:// /stackoverflow.com/questions/19394570/java-jre-7u45-breaks-classloader-getresources)。在 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
。
2.8.3. FileSystemResource
注意事项
未附加到 FileSystemResource
的 FileSystemApplicationContext
(即,当 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
一起使用,并通过使用file:
URL 前缀强制使用 UrlResource
。以下示例展示了如何执行此操作:
// 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");
评论区