`

spring如何解析通配符路径

 
阅读更多

转自: http://goodscript.iteye.com/blog/1161519

在spring的配置文件中、经常看见类似这样的配置路径: 

Java代码  收藏代码
  1. classpath:/com/module/**/*sql.xml  


系统会根据配置路径自动加载符合路径规则的xml文件 
假如让你实现这样的功能: 
根据一个通配符路径加载符合规则的xml文件你会怎么做? 

先看一个小例子: 

Java代码  收藏代码
  1. import java.io.IOException;  
  2.   
  3. import org.springframework.core.io.Resource;  
  4. import org.springframework.core.io.support.PathMatchingResourcePatternResolver;  
  5. import org.springframework.core.io.support.ResourcePatternResolver;  
  6.   
  7. public class XMLManager {  
  8.   
  9.     private String location = "classpath:*.xml";  
  10.   
  11.     public void readFile() throws IOException {  
  12.         ResourcePatternResolver resourceLoader = new PathMatchingResourcePatternResolver();  
  13.         Resource[] source = resourceLoader.getResources(location);  
  14.         for (int i = 0; i < source.length; i++) {  
  15.             Resource resource = source[i];  
  16.             System.out.println(resource.getFilename());  
  17.   
  18.         }  
  19.     }  
  20.   
  21.     public static void main(String[] args) {  
  22.   
  23.         XMLManager m = new XMLManager();  
  24.         try {  
  25.             m.readFile();  
  26.         } catch (IOException e) {  
  27.             e.printStackTrace();  
  28.         }  
  29.     }  
  30. }  



输出结果: 

Java代码  收藏代码
  1. applicationContext.xml  
  2. logback.xml  
  3. menu_my.xml  


是不是很简单? 
只要调用PathMatchingResourcePatternResolver的getResources方法就可以实现我们想要的功能。 
下面深入研究一下spring的源码PathMatchingResourcePatternResolver: 
1、getResources方法 

Java代码  收藏代码
  1. public Resource[] getResources(String locationPattern) throws IOException {  
  2.         Assert.notNull(locationPattern, "Location pattern must not be null");  
  3.         if (locationPattern.startsWith(CLASSPATH_ALL_URL_PREFIX)) {  
  4.             // a class path resource (multiple resources for same name possible)  
  5.             if (getPathMatcher().isPattern(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length()))) {  
  6.                 // a class path resource pattern  
  7.                 return findPathMatchingResources(locationPattern);  
  8.             }  
  9.             else {  
  10.                 // all class path resources with the given name  
  11.                 return findAllClassPathResources(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length()));  
  12.             }  
  13.         }  
  14.         else {  
  15.             // Only look for a pattern after a prefix here  
  16.             // (to not get fooled by a pattern symbol in a strange prefix).  
  17.             int prefixEnd = locationPattern.indexOf(":") + 1;  
  18.             if (getPathMatcher().isPattern(locationPattern.substring(prefixEnd))) {  
  19.                 // a file pattern  
  20.                 return findPathMatchingResources(locationPattern);  
  21.             }  
  22.             else {  
  23.                 // a single resource with the given name  
  24.                 return new Resource[] {getResourceLoader().getResource(locationPattern)};  
  25.             }  
  26.         }  
  27.     }  


该方法主要是判断locationPattern是否包含有通配符、如果包含通配符则调用findPathMatchingResources方法、没有包含通配符就不需要解析了 
2、findPathMatchingResources方法 

Java代码  收藏代码
  1. protected Resource[] findPathMatchingResources(String locationPattern) throws IOException {  
  2.     String rootDirPath = determineRootDir(locationPattern);  
  3.     String subPattern = locationPattern.substring(rootDirPath.length());  
  4.     Resource[] rootDirResources = getResources(rootDirPath);  
  5.     Set<Resource> result = new LinkedHashSet<Resource>(16);  
  6.     for (Resource rootDirResource : rootDirResources) {  
  7.         rootDirResource = resolveRootDirResource(rootDirResource);  
  8.         if (isJarResource(rootDirResource)) {  
  9.             result.addAll(doFindPathMatchingJarResources(rootDirResource, subPattern));  
  10.         }  
  11.         else if (rootDirResource.getURL().getProtocol().startsWith(ResourceUtils.URL_PROTOCOL_VFS)) {  
  12.             result.addAll(VfsResourceMatchingDelegate.findMatchingResources(rootDirResource, subPattern, getPathMatcher()));  
  13.         }  
  14.         else {  
  15.             result.addAll(doFindPathMatchingFileResources(rootDirResource, subPattern));  
  16.         }  
  17.     }  
  18.     if (logger.isDebugEnabled()) {  
  19.         logger.debug("Resolved location pattern [" + locationPattern + "] to resources " + result);  
  20.     }  
  21.     return result.toArray(new Resource[result.size()]);  
  22. }  


把locationPattern拆分成两部分:rootDirPath 和subPattern 
rootDirPath是根目录路径 
subPattern是子目录路径匹配规则字符串 
历遍根目录下的所有子目录、并得到所有的子目录 
在doFindPathMatchingFileResources(rootDirResource, subPattern)方法中 
再根据子目录逐个逐个去匹配subPattern 
3、doFindPathMatchingFileResources 

Java代码  收藏代码
  1. protected Set<Resource> doFindPathMatchingFileResources(Resource rootDirResource, String subPattern)  
  2.         throws IOException {  
  3.   
  4.     File rootDir;  
  5.     try {  
  6.         rootDir = rootDirResource.getFile().getAbsoluteFile();  
  7.     }  
  8.     catch (IOException ex) {  
  9.         if (logger.isWarnEnabled()) {  
  10.             logger.warn("Cannot search for matching files underneath " + rootDirResource +  
  11.                     " because it does not correspond to a directory in the file system", ex);  
  12.         }  
  13.         return Collections.emptySet();  
  14.     }  
  15.     return doFindMatchingFileSystemResources(rootDir, subPattern);  
  16. }  


跳转到另一个方法doFindMatchingFileSystemResources: 

Java代码  收藏代码
  1. protected Set<Resource> doFindMatchingFileSystemResources(File rootDir, String subPattern) throws IOException {  
  2.     if (logger.isDebugEnabled()) {  
  3.         logger.debug("Looking for matching resources in directory tree [" + rootDir.getPath() + "]");  
  4.     }  
  5.     Set<File> matchingFiles = retrieveMatchingFiles(rootDir, subPattern);  
  6.     Set<Resource> result = new LinkedHashSet<Resource>(matchingFiles.size());  
  7.     for (File file : matchingFiles) {  
  8.         result.add(new FileSystemResource(file));  
  9.     }  
  10.     return result;  
  11. }  


retrieveMatchingFiles 

Java代码  收藏代码
  1. protected Set<File> retrieveMatchingFiles(File rootDir, String pattern) throws IOException {  
  2.     if (!rootDir.exists()) {  
  3.         // Silently skip non-existing directories.  
  4.         if (logger.isDebugEnabled()) {  
  5.             logger.debug("Skipping [" + rootDir.getAbsolutePath() + "] because it does not exist");  
  6.         }  
  7.         return Collections.emptySet();  
  8.     }  
  9.     if (!rootDir.isDirectory()) {  
  10.         // Complain louder if it exists but is no directory.  
  11.         if (logger.isWarnEnabled()) {  
  12.             logger.warn("Skipping [" + rootDir.getAbsolutePath() + "] because it does not denote a directory");  
  13.         }  
  14.         return Collections.emptySet();  
  15.     }  
  16.     if (!rootDir.canRead()) {  
  17.         if (logger.isWarnEnabled()) {  
  18.             logger.warn("Cannot search for matching files underneath directory [" + rootDir.getAbsolutePath() +  
  19.                     "] because the application is not allowed to read the directory");  
  20.         }  
  21.         return Collections.emptySet();  
  22.     }  
  23.     String fullPattern = StringUtils.replace(rootDir.getAbsolutePath(), File.separator, "/");  
  24.     if (!pattern.startsWith("/")) {  
  25.         fullPattern += "/";  
  26.     }  
  27.     fullPattern = fullPattern + StringUtils.replace(pattern, File.separator, "/");  
  28.     Set<File> result = new LinkedHashSet<File>(8);  
  29.     doRetrieveMatchingFiles(fullPattern, rootDir, result);  
  30.     return result;  
  31. }  


调用递归方法: 
doRetrieveMatchingFiles 

Java代码  收藏代码
  1. protected void doRetrieveMatchingFiles(String fullPattern, File dir, Set<File> result) throws IOException {  
  2.     if (logger.isDebugEnabled()) {  
  3.         logger.debug("Searching directory [" + dir.getAbsolutePath() +  
  4.                 "] for files matching pattern [" + fullPattern + "]");  
  5.     }  
  6.     File[] dirContents = dir.listFiles();  
  7.     if (dirContents == null) {  
  8.         if (logger.isWarnEnabled()) {  
  9.             logger.warn("Could not retrieve contents of directory [" + dir.getAbsolutePath() + "]");  
  10.         }  
  11.         return;  
  12.     }  
  13.     for (File content : dirContents) {  
  14.         String currPath = StringUtils.replace(content.getAbsolutePath(), File.separator, "/");  
  15.         if (content.isDirectory() && getPathMatcher().matchStart(fullPattern, currPath + "/")) {  
  16.             if (!content.canRead()) {  
  17.                 if (logger.isDebugEnabled()) {  
  18.                     logger.debug("Skipping subdirectory [" + dir.getAbsolutePath() +  
  19.                             "] because the application is not allowed to read the directory");  
  20.                 }  
  21.             }  
  22.             else {  
  23.                 doRetrieveMatchingFiles(fullPattern, content, result);  
  24.             }  
  25.         }  
  26.         if (getPathMatcher().match(fullPattern, currPath)) {  
  27.             result.add(content);  
  28.         }  
  29.     }  
  30. }  
分享到:
评论

相关推荐

    Spring源码含有通配符路径解析一[文].pdf

    在Spring框架中,资源路径解析是一项关键功能,它允许开发者使用通配符来加载一系列相关的配置文件或资源。本文将深入探讨Spring如何处理包含通配符的路径,特别是当路径以`classpath*`开头时的情况。 首先,让我们...

    Java使用路径通配符加载Resource与profiles配置使用详解

    Ant路径通配符是Spring提供的一种强大的通配符匹配机制,能够从一个路径匹配一批资源。Ant路径通配符支持三种通配符:?、*、。 * ?:匹配一个字符,如“config?.xml”将匹配“config1.xml”。 * *:匹配零个或多...

    spring mvc路径匹配原则详解

    默认的策略实现了 `org.springframework.util.AntPathMatcher`,使用了 Apache Ant 样式的路径,这种路径模式有三种通配符匹配方法: * `?` 匹配任何单字符 * `*` 匹配 0 或者任意数量的字符 * `` 匹配 0 或者更多...

    Spring中使用classpath加载配置文件浅析

    1. **不使用通配符**:当配置文件路径不包含通配符时,Spring会直接定位到指定的文件。例如: - 当配置文件直接放置在应用的bin目录下的conf文件夹内时,上述代码将加载该目录下的`application-context.xml`文件。...

    跟我学Spring,Spring3学习资料

    - **Resource通配符路径:** 提供了类似于Ant风格的路径模式匹配,用于访问多个资源。 ### 5. Spring表达式语言(SpEL) - **SpEL概述:** 简介了SpEL的用途以及基本语法。 - **SpEL基础与语法:** 详细解释了SpEL...

    Spring-Reference_zh_CN(Spring中文参考手册)

    4.7.2. Application context构造器中资源路径的通配符 4.7.2.1. Ant风格的pattern 4.7.2.2. classpath*: 前缀 4.7.2.3. 其他关于通配符的说明 4.7.3. FileSystemResource 提示 5. 校验,数据绑定,BeanWrapper,与...

    spring的学习笔记

    - **4.4 Resource通配符路径**:支持使用通配符加载一组资源,方便进行批量操作。 ### 5. **Spring Expression Language (SpEL)** SpEL是Spring提供的强大表达式语言,用于在运行时查询和操作Bean的属性,以及执行...

    跟我学spring3(1-7)

    5. **资源管理**:Spring提供了对资源(如文件、数据库连接等)的管理,包括基础知识、内置Resource实现和访问Resource的方法,以及使用Resource通配符路径来灵活地加载资源。 6. **Spring表达式语言(SpEL)**:...

    Spring简单URL映射例子

    在实际应用中,我们可能需要处理更复杂的URL映射,如使用通配符、路径变量等。例如,`@RequestMapping("/users/{userId}")`会将URL中的"{userId}"部分作为路径变量传入方法。 为了运行此示例,还需要确保Spring的...

    跟我学spring

    4.1节介绍资源基础知识,4.2节探讨Spring内置的Resource实现,4.3节介绍如何访问这些资源,4.4节讲解Resource通配符路径的使用。 【第五章】Spring表达式语言(SpEL)是一个强大的表达式语言,支持在运行时查询和...

    跟我学spring3 .pdf

    4.1章节至4.4章节讨论了Spring如何管理和访问资源,包括内置的Resource实现、资源的通配符路径以及不同类型的Resource接口,这些都是构建可扩展且健壮的应用不可或缺的部分。 **Spring表达式语言(SpEL)** SpEL是...

    spring-MVC搭建所需包(spring3.0)附带搭建源码

    - 开源项目:通过阅读和分析开源项目中的Spring MVC代码,可以学习到实际应用场景下的最佳实践。 总之,Spring MVC提供了一种强大且灵活的方式来构建Web应用程序,其注解驱动的特性极大地简化了开发流程。通过理解...

    浅析Spring配置中的classpath:与classpath*:的区别

    1. 从上面的使用场景看,可以在路径上使用通配符*进行模糊查找。例如:&lt;param-value&gt;classpath:applicationContext-*.xml 2. "/" 表示的是任意目录;"/applicationContext-*.xml" 表示任意目录下的以 ...

    跟开涛学Spring

    1.14 【第四章】 资源 之 4.4 Resource通配符路径 ——跟我学spring3 . . . . . . . . . . . . . . . . . . . . . . . .171 1.15 【第五章】Spring表达式语言 之 5.1 概述 5.2 SpEL基础 ——跟我学spring3 . . . . ...

    MyBatis 3 整合Spring3、SpringMVC

    - 设置`contextConfigLocation`参数,指定Spring配置文件的位置,可以使用通配符加载多个XML配置文件。 - 配置Spring MVC的核心Servlet`DispatcherServlet`,并指定初始化参数`contextConfigLocation`,指定其配置...

    Spring 2.0 开发参考手册

    4.7.2. Application context构造器中资源路径的通配符 4.7.3. FileSystemResource 提示 5. 校验,数据绑定,BeanWrapper,与属性编辑器 5.1. 简介 5.2. 使用Spring的Validator接口进行校验 5.3. 从错误代码到...

    spring管理struts的action的代码

    这里的`classpath*`是一个通配符,它可以匹配类路径下的多个资源,其中星号(`*`)表示任意多个字符。 - `&lt;listener&gt;`定义了一个监听器`ContextLoaderListener`,它会监听Web应用的启动和关闭事件,并根据`...

    Spring学习总结笔记

    - **WildcardClassLoader**:通过通配符加载多个配置文件,如`classpath:applicationContext-*.xml`。 5. **依赖注入(Dependency Injection, DI)** DI是Spring的核心,它通过XML配置或注解方式来实现对象间的...

    Spring中如何加载多个配置文件.pdf

    `resource`属性指定了被导入配置文件的路径,该路径相对于主配置文件的位置。 ### 小结 以上三种方式均可实现在Spring框架中加载多个配置文件的需求。选择哪种方式取决于项目的具体需求和个人偏好: - 如果需要...

    跟我学Spring

    - **4.4 Resource通配符路径**:探讨了如何使用通配符在Spring中加载资源文件。 8. **Spring表达式语言(SpEL)**: - **5.1 概述**:简述了SpEL的作用和重要性,它是Spring框架中用于在运行时表达和评估表达式的...

Global site tag (gtag.js) - Google Analytics