Application Context 构造器的 Resource 路径中的通配符

注意事项:只能使用在 ApplicationContext 的构造器的字符串路径中,与 Resource 类型没有任何关系,一个 Resource 一次只能指定一个 resource 数据源,不能在构造一个实际的 Resource 时,路径中包含这些通配符。

Note that this wildcarding is specific to the use of resource paths in application context constructors (or when you use the PathMatcher utility class hierarchy directly) and is resolved at construction time. It has nothing to do with the Resource type itself. You cannot use the classpath*: prefix to construct an actual Resource, as a resource points to just one resource at a time.

classpath* 前缀

在 ApplicationContext 的构造器中,指定 bean 定义的 xml 文件时,可以使用通配符 classpath* 前缀,如果在多个 classpath 目录下都存在相同名称的文件,且匹配路径中的文件名,首先会通过调用 ClassLoader.getResources(…)) 来获取每个 classpath 下文件对应的 URL, 然后合并作为最终的上下文 bean 定义

This special prefix specifies that all classpath resources that match the given name must be obtained (internally, this essentially happens through a call to ClassLoader.getResources(…)) and then merged to form the final application context definition.

https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#resources-resourceloaderaware

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
  /**
* resources/test.xml
* E:/DevelopmentKit/ClasspathOutofIdea/test.xml 指定为 classpath 中 (File -> Project Structure -> SDKS -> classpath)
* 上面的两个路径都为 classpath, 并且包含了同名的 bean 定义 xml 文件中,分别定义了 Date bean 和 Mp3Song bean
*/
public static void resources() {
try {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath*:test.xml");
String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
System.out.println("beanDefinitionName = " + beanDefinitionName);
}

Enumeration<URL> resources1 = applicationContext.getClassLoader().getResources("test.xml");
while (resources1.hasMoreElements()) {
URL url = resources1.nextElement();
System.out.println("url = " + url);
}
} catch (IOException e) {
e.printStackTrace();
}
}

结果:

1
2
3
4
beanDefinitionName = java.util.Date#0
beanDefinitionName = com.something.learn.bean.Mp3Song#0
url = file:/E:/DevelopmentKit/ClasspathOutofIdea/test.xml
url = file:/E:/DevelopmentKit/idea-workspace/java-workspace/spring_loader_bean/target/classes/test.xml

Ant-style 匹配表达式

(matched by using Spring’s PathMatcher utility)

ant 风格的表达式也可以使用在 Application Context 的构造器路径中,如 classpath:com/mycompany/**/service-context.xml, 此时,会通过调用 ClassLoader.getResource(…)), 传入最后的非通配符片段,返回一个 URL 对象,如果是非 jar: 形式的 URL, 会从中获取 java.io.File 对象,通过遍历文件系统来解析通配符。

Ant-style的匹配原则

Apache Ant样式的路径有三种通配符匹配方法(在下面的表格中列出)

路径 描述
? 匹配任何单字符
* 匹配0或者任意数量的字符
** 匹配0或者更多的目录

Table Example Ant-Style Path Patterns

Path Description
/app/*.x 匹配(Matches)所有在app路径下的.x文件
/app/p?ttern 匹配(Matches) /app/pattern 和 /app/pXttern 但是不包括/app/pttern
/**/example 匹配(Matches) /app/example/app/foo/example, 和 /example
/app/**/dir/file. 匹配(Matches) /app/dir/file.jsp, /app/foo/dir/file.html,/app/foo/bar/dir/file.pdf, 和 /app/dir/file.java
/*/.jsp 匹配(Matches)任何的.jsp 文件

可以结合 classpath* 和 ant-style 的表达式,如:

1
classpath*:com/mycompany/**/service-context.xml

注意事项:

Note that classpath*:, when combined with Ant-style patterns, only works reliably with at least one root directory before the pattern starts, unless the actual target files reside in the file system. This means that a pattern such as classpath*:*.xml might not retrieve files from the root of jar files but rather only from the root of expanded directories.

https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#resources-app-ctx-ant-patterns-in-paths

1
2
3
4
EnvironmentPostProcessor
PathMatchingResourcePatternResolver
ResourcePropertySource
EncodedResource