2.8. 应用程序上下文和资源路径
本节介绍如何使用资源创建应用程序上下文,包括使用 XML 的快捷方式、如何使用通配符以及其他详细信息。
2.8.1. 构建应用程序上下文
应用程序上下文构造函数(针对特定应用程序上下文类型)通常采用字符串或字符串数组作为资源的位置路径,例如构成上下文定义的 XML 文件。
当这样的位置路径没有前缀时,Resource
从该路径构建并用于加载 bean 定义的特定类型取决于并适用于特定的应用程序上下文。例如,考虑以下示例,该示例创建一个 ClassPathXmlApplicationContext
:
bean 定义是从类路径加载的,因为使用了ClassPathResource
。但是,请考虑以下示例,该示例创建一个FileSystemXmlApplicationContext
:
现在 bean 定义从文件系统位置加载(在这种情况下,相对于当前工作目录)。
请注意,在位置路径上使用特殊的类路径前缀或标准 URL 前缀会覆盖为加载 bean 定义而创建的默认资源类型。考虑以下示例:
使用FileSystemXmlApplicationContext
从类路径加载 bean 定义。但是,它仍然是一个 FileSystemXmlApplicationContext
。如果随后将其用作 ResourceLoader,则任何无前缀的路径仍将被视为文件系统路径。
构造ClassPathXmlApplicationContext
实例——快捷方式
ClassPathXmlApplicationContext
公开了许多构造函数以实现方便的实例化。基本思想是您可以仅提供一个字符串数组,该数组仅包含 XML 文件本身的文件名(没有前导路径信息),还可以提供一个Class
. 然后ClassPathXmlApplicationContext
从提供的类派生路径信息。
考虑以下目录布局:
以下示例显示了如何实例化由名为services.xml
和 repositories.xml
(位于类路径上)的文件中定义的 bean 组成的 ClassPathXmlApplicationContext
实例:
有关各种构造函数的详细信息,请参阅ClassPathXmlApplicationContext
javadoc。
2.8.2. 应用程序上下文构造函数资源路径中的通配符
应用程序上下文构造函数值中的资源路径可能是简单路径(如前所示),每个路径都具有到目标Resource
的一对一映射,或者,可能包含特殊classpath*:
前缀或内部 Ant 样式模式(匹配使用 Spring 的PathMatcher
实用程序)。后者都是有效的通配符。
这种机制的一个用途是当您需要进行组件式应用程序组装时。所有组件都可以将上下文定义片段发布到一个众所周知的位置路径,并且,当最终应用程序上下文使用以 classpath*:
为前缀的相同路径创建时 ,所有组件片段都会被自动拾取。
请注意,此通配符特定于应用程序上下文构造函数中资源路径的使用(或当您PathMatcher
直接使用实用程序类层次结构时),并在构造时解析。Resource
它与类型本身无关。您不能使用classpath*:
前缀来构造实际的Resource
,因为资源一次仅指向一个资源。
Ant样式的模式
路径位置可以包含 Ant 样式的模式,如以下示例所示:
当路径位置包含 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*:
前缀,如以下示例所示:
这个特殊的前缀指定必须获取与给定名称匹配的所有类路径资源(在内部,这基本上是通过对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 样式模式找到匹配的资源。考虑以下资源位置示例:
现在考虑一个可能有人用来尝试查找该文件的 Ant 样式路径:
这样的资源可能只存在于类路径中的一个位置,但是当使用诸如前面的示例之类的路径来尝试解析它时,解析器会处理 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
实例将所有位置路径视为相对路径,无论它们是否以前导斜杠开头。实际上,这意味着以下示例是等效的:
以下示例也是等价的(即使它们不同是有意义的,因为一种情况是相对的,另一种是绝对的):
实际上,如果您需要真正的绝对文件系统路径,则应避免将绝对路径与 FileSystemResource
或 FileSystemXmlApplicationContext
一起使用,并通过使用file:
URL 前缀强制使用 UrlResource
。以下示例展示了如何执行此操作:
最后更新于