入口
ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:bean*.xml");
/** * Main entry point. * @return {@code true} if the string matches against the pattern, or {@code false} otherwise. */ public boolean matchStrings(String str, Map<String, String> uriTemplateVariables) { Matcher matcher = this.pattern.matcher(str); if (matcher.matches()) { if (uriTemplateVariables != null) { // SPR-8455 Assert.isTrue(this.variableNames.size() == matcher.groupCount(), "The number of capturing groups in the pattern segment " + this.pattern + " does not match the number of URI template variables it defines, which can occur if " + " capturing groups are used in a URI template regex. Use non-capturing groups instead."); for (int i = 1; i <= matcher.groupCount(); i++) { String name = this.variableNames.get(i - 1); String value = matcher.group(i); uriTemplateVariables.put(name, value); } } return true; } else { return false; } } }
最后发现 java.util.regex.Pattern 调用matches() 方法
从而得知 支持正则表达式。
总结:
classpath:bean*.xml冒号前半部分是为了获取 classpath 文件路径,然后file.lists() 递归循环获取所有 文件路径 ,逐一与冒号后面的 pattern 匹配。
冒号分析
/** * A {@link ResourcePatternResolver} implementation that is able to resolve a * specified resource location path into one or more matching Resources. * The source path may be a simple path which has a one-to-one mapping to a * target {@link org.springframework.core.io.Resource}, or alternatively * may contain the special "{@code classpath*:}" prefix and/or * internal Ant-style regular expressions (matched using Spring‘s * {@link org.springframework.util.AntPathMatcher} utility). * Both of the latter are effectively wildcards. * * <p><b>No Wildcards:</b> * * <p>In the simple case, if the specified location path does not start with the * {@code "classpath*:}" prefix, and does not contain a PathMatcher pattern, * this resolver will simply return a single resource via a * {@code getResource()} call on the underlying {@code ResourceLoader}. * Examples are real URLs such as "{@code file:C:/context.xml}", pseudo-URLs * such as "{@code classpath:/context.xml}", and simple unprefixed paths * such as "{@code /WEB-INF/context.xml}". The latter will resolve in a * fashion specific to the underlying {@code ResourceLoader} (e.g. * {@code ServletContextResource} for a {@code WebApplicationContext}). * * <p><b>Ant-style Patterns:</b> * * <p>When the path location contains an Ant-style pattern, e.g.: * <pre class="code"> * /WEB-INF/*-context.xml * com/mycompany/**/applicationContext.xml * file:C:/some/path/*-context.xml * classpath:com/mycompany/**/applicationContext.xml</pre> * the resolver follows a more complex but defined procedure to try to resolve * the wildcard. It produces a {@code Resource} for the path up to the last * non-wildcard segment and obtains a {@code URL} from it. If this URL is * not a "{@code jar:}" URL or container-specific variant (e.g. * "{@code zip:}" in WebLogic, "{@code wsjar}" in WebSphere", etc.), * then a {@code java.io.File} is obtained from it, and used to resolve the * wildcard by walking the filesystem. In the case of a jar URL, the resolver * either gets a {@code java.net.JarURLConnection} from it, or manually parses * the jar URL, and then traverses the contents of the jar file, to resolve the * wildcards. * * <p><b>Implications on portability:</b> * * <p>If the specified path is already a file URL (either explicitly, or * implicitly because the base {@code ResourceLoader} is a filesystem one, * then wildcarding is guaranteed to work in a completely portable fashion. * * <p>If the specified path is a classpath location, then the resolver must * obtain the last non-wildcard path segment URL via a * {@code Classloader.getResource()} call. Since this is just a * node of the path (not the file at the end) it is actually undefined * (in the ClassLoader Javadocs) exactly what sort of a URL is returned in * this case. In practice, it is usually a {@code java.io.File} representing * the directory, where the classpath resource resolves to a filesystem * location, or a jar URL of some sort, where the classpath resource resolves * to a jar location. Still, there is a portability concern on this operation. * * <p>If a jar URL is obtained for the last non-wildcard segment, the resolver * must be able to get a {@code java.net.JarURLConnection} from it, or * manually parse the jar URL, to be able to walk the contents of the jar, * and resolve the wildcard. This will work in most environments, but will * fail in others, and it is strongly recommended that the wildcard * resolution of resources coming from jars be thoroughly tested in your * specific environment before you rely on it. * * <p><b>{@code classpath*:} Prefix:</b> * * <p>There is special support for retrieving multiple class path resources with * the same name, via the "{@code classpath*:}" prefix. For example, * "{@code classpath*:META-INF/beans.xml}" will find all "beans.xml" * files in the class path, be it in "classes" directories or in JAR files. * This is particularly useful for autodetecting config files of the same name * at the same location within each jar file. Internally, this happens via a * {@code ClassLoader.getResources()} call, and is completely portable. * * <p>The "classpath*:" prefix can also be combined with a PathMatcher pattern in * the rest of the location path, for example "classpath*:META-INF/*-beans.xml". * In this case, the resolution strategy is fairly simple: a * {@code ClassLoader.getResources()} call is used on the last non-wildcard * path segment to get all the matching resources in the class loader hierarchy, * and then off each resource the same PathMatcher resolution strategy described * above is used for the wildcard subpath. * * <p><b>Other notes:</b> * * <p><b>WARNING:</b> Note that "{@code classpath*:}" when combined with * Ant-style patterns will only work 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 like "{@code classpath*:*.xml}" will * <i>not</i> retrieve files from the root of jar files but rather only from the * root of expanded directories. This originates from a limitation in the JDK‘s * {@code ClassLoader.getResources()} method which only returns file system * locations for a passed-in empty String (indicating potential roots to search). * * <p><b>WARNING:</b> Ant-style patterns with "classpath:" resources are not * guaranteed to find matching resources if the root package to search is available * in multiple class path locations. This is because a resource such as * <pre class="code"> * com/mycompany/package1/service-context.xml * </pre> * may be in only one location, but when a path such as * <pre class="code"> * classpath:com/mycompany/**/service-context.xml * </pre> * is used to try to resolve it, the resolver will work off the (first) URL * returned by {@code getResource("com/mycompany");}. If this base package * node exists in multiple classloader locations, the actual end resource may * not be underneath. Therefore, preferably, use "{@code classpath*:}" with the same * Ant-style pattern in such a case, which will search <i>all</i> class path * locations that contain the root package. * * @author Juergen Hoeller * @author Colin Sampaleanu * @author Marius Bogoevici * @author Costin Leau * @since 1.0.2 * @see #CLASSPATH_ALL_URL_PREFIX * @see org.springframework.util.AntPathMatcher * @see org.springframework.core.io.ResourceLoader#getResource(String) * @see ClassLoader#getResources(String) */ public class PathMatchingResourcePatternResolver implements ResourcePatternResolver
PathMatchingResourcePatternResolver 的部分方法↓
1 @Override 2 public Resource[] getResources(String locationPattern) throws IOException { 3 Assert.notNull(locationPattern, "Location pattern must not be null"); 4 if (locationPattern.startsWith(CLASSPATH_ALL_URL_PREFIX)) { 5 // a class path resource (multiple resources for same name possible) 6 if (getPathMatcher().isPattern(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length()))) { 7 // a class path resource pattern 8 return findPathMatchingResources(locationPattern); 9 } 10 else { 11 // all class path resources with the given name 12 return findAllClassPathResources(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length())); 13 } 14 } 15 else { 16 // Only look for a pattern after a prefix here 17 // (to not get fooled by a pattern symbol in a strange prefix). 18 int prefixEnd = locationPattern.indexOf(":") + 1; 19 if (getPathMatcher().isPattern(locationPattern.substring(prefixEnd))) { 20 // a file pattern 21 return findPathMatchingResources(locationPattern); 22 } 23 else { 24 // a single resource with the given name 25 return new Resource[] {getResourceLoader().getResource(locationPattern)}; 26 } 27 } 28 }
locationPattern 的两次值分别是:
- classpath:bean*.xml
- classpath:
第8行↑ 调用的方法参数是1,在该方法中再一次调用getResources,然后传的参数是2 (目的是为了获取rootDirResources)
第一个if else 是区分classpath*: 这是固定写法↓ ,然后回处理冒号左右↑
/** * Pseudo URL prefix for all matching resources from the class path: "classpath*:" * This differs from ResourceLoader‘s classpath URL prefix in that it * retrieves all matching resources for a given name (e.g. "/beans.xml"), * for example in the root of all deployed JAR files. * @see org.springframework.core.io.ResourceLoader#CLASSPATH_URL_PREFIX */ String CLASSPATH_ALL_URL_PREFIX = "classpath*:";
如果是classpath: 这是固定写法↓ ,则处理冒号左右
/** Pseudo URL prefix for loading from the class path: "classpath:" */ String CLASSPATH_URL_PREFIX = ResourceUtils.CLASSPATH_URL_PREFIX;
如果是冒号右边是路径,则处理这个资源。↑
如果是冒号右边不是路径,则继续处理。↑【25行】——如下:
1 @Override 2 public Resource getResource(String location) { 3 Assert.notNull(location, "Location must not be null"); 4 if (location.startsWith("/")) { 5 return getResourceByPath(location); 6 } 7 else if (location.startsWith(CLASSPATH_URL_PREFIX)) { 8 return new ClassPathResource(location.substring(CLASSPATH_URL_PREFIX.length()), getClassLoader()); 9 } 10 else { 11 try { 12 // Try to parse the location as a URL... 13 URL url = new URL(location); 14 return new UrlResource(url); 15 } 16 catch (MalformedURLException ex) { 17 // No URL -> resolve as resource path. 18 return getResourceByPath(location); 19 } 20 } 21 }
第7行,必须以classpath: 开始。↑
第8行,new ClassPathResource 的实例,其中第一个参数path为"" ,第二个参数为getClassLoader() 返回的实例。↑
1 protected URL resolveURL() { 2 if (this.clazz != null) { 3 return this.clazz.getResource(this.path); 4 } 5 else if (this.classLoader != null) { 6 return this.classLoader.getResource(this.path); 7 } 8 else { 9 return ClassLoader.getSystemResource(this.path); 10 } 11 }
第6行 ,返回了类路径。↑ 结果如下:↓
file:/E:/e/workspace/context/target/classes/
时间: 2024-10-14 07:43:57