`
goodscript
  • 浏览: 72932 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

spring如何解析通配符路径

阅读更多
在spring的配置文件中、经常看见类似这样的配置路径:
classpath:/com/module/**/*sql.xml

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

先看一个小例子:
import java.io.IOException;

import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;

public class XMLManager {

	private String location = "classpath:*.xml";

	public void readFile() throws IOException {
		ResourcePatternResolver resourceLoader = new PathMatchingResourcePatternResolver();
		Resource[] source = resourceLoader.getResources(location);
		for (int i = 0; i < source.length; i++) {
			Resource resource = source[i];
			System.out.println(resource.getFilename());

		}
	}

	public static void main(String[] args) {

		XMLManager m = new XMLManager();
		try {
			m.readFile();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}


输出结果:
applicationContext.xml
logback.xml
menu_my.xml

是不是很简单?
只要调用PathMatchingResourcePatternResolver的getResources方法就可以实现我们想要的功能。
下面深入研究一下spring的源码PathMatchingResourcePatternResolver:
1、getResources方法
public Resource[] getResources(String locationPattern) throws IOException {
		Assert.notNull(locationPattern, "Location pattern must not be null");
		if (locationPattern.startsWith(CLASSPATH_ALL_URL_PREFIX)) {
			// a class path resource (multiple resources for same name possible)
			if (getPathMatcher().isPattern(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length()))) {
				// a class path resource pattern
				return findPathMatchingResources(locationPattern);
			}
			else {
				// all class path resources with the given name
				return findAllClassPathResources(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length()));
			}
		}
		else {
			// Only look for a pattern after a prefix here
			// (to not get fooled by a pattern symbol in a strange prefix).
			int prefixEnd = locationPattern.indexOf(":") + 1;
			if (getPathMatcher().isPattern(locationPattern.substring(prefixEnd))) {
				// a file pattern
				return findPathMatchingResources(locationPattern);
			}
			else {
				// a single resource with the given name
				return new Resource[] {getResourceLoader().getResource(locationPattern)};
			}
		}
	}

该方法主要是判断locationPattern是否包含有通配符、如果包含通配符则调用findPathMatchingResources方法、没有包含通配符就不需要解析了
2、findPathMatchingResources方法
	protected Resource[] findPathMatchingResources(String locationPattern) throws IOException {
		String rootDirPath = determineRootDir(locationPattern);
		String subPattern = locationPattern.substring(rootDirPath.length());
		Resource[] rootDirResources = getResources(rootDirPath);
		Set<Resource> result = new LinkedHashSet<Resource>(16);
		for (Resource rootDirResource : rootDirResources) {
			rootDirResource = resolveRootDirResource(rootDirResource);
			if (isJarResource(rootDirResource)) {
				result.addAll(doFindPathMatchingJarResources(rootDirResource, subPattern));
			}
			else if (rootDirResource.getURL().getProtocol().startsWith(ResourceUtils.URL_PROTOCOL_VFS)) {
				result.addAll(VfsResourceMatchingDelegate.findMatchingResources(rootDirResource, subPattern, getPathMatcher()));
			}
			else {
				result.addAll(doFindPathMatchingFileResources(rootDirResource, subPattern));
			}
		}
		if (logger.isDebugEnabled()) {
			logger.debug("Resolved location pattern [" + locationPattern + "] to resources " + result);
		}
		return result.toArray(new Resource[result.size()]);
	}

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

		File rootDir;
		try {
			rootDir = rootDirResource.getFile().getAbsoluteFile();
		}
		catch (IOException ex) {
			if (logger.isWarnEnabled()) {
				logger.warn("Cannot search for matching files underneath " + rootDirResource +
						" because it does not correspond to a directory in the file system", ex);
			}
			return Collections.emptySet();
		}
		return doFindMatchingFileSystemResources(rootDir, subPattern);
	}

跳转到另一个方法doFindMatchingFileSystemResources:
	protected Set<Resource> doFindMatchingFileSystemResources(File rootDir, String subPattern) throws IOException {
		if (logger.isDebugEnabled()) {
			logger.debug("Looking for matching resources in directory tree [" + rootDir.getPath() + "]");
		}
		Set<File> matchingFiles = retrieveMatchingFiles(rootDir, subPattern);
		Set<Resource> result = new LinkedHashSet<Resource>(matchingFiles.size());
		for (File file : matchingFiles) {
			result.add(new FileSystemResource(file));
		}
		return result;
	}

retrieveMatchingFiles

	protected Set<File> retrieveMatchingFiles(File rootDir, String pattern) throws IOException {
		if (!rootDir.exists()) {
			// Silently skip non-existing directories.
			if (logger.isDebugEnabled()) {
				logger.debug("Skipping [" + rootDir.getAbsolutePath() + "] because it does not exist");
			}
			return Collections.emptySet();
		}
		if (!rootDir.isDirectory()) {
			// Complain louder if it exists but is no directory.
			if (logger.isWarnEnabled()) {
				logger.warn("Skipping [" + rootDir.getAbsolutePath() + "] because it does not denote a directory");
			}
			return Collections.emptySet();
		}
		if (!rootDir.canRead()) {
			if (logger.isWarnEnabled()) {
				logger.warn("Cannot search for matching files underneath directory [" + rootDir.getAbsolutePath() +
						"] because the application is not allowed to read the directory");
			}
			return Collections.emptySet();
		}
		String fullPattern = StringUtils.replace(rootDir.getAbsolutePath(), File.separator, "/");
		if (!pattern.startsWith("/")) {
			fullPattern += "/";
		}
		fullPattern = fullPattern + StringUtils.replace(pattern, File.separator, "/");
		Set<File> result = new LinkedHashSet<File>(8);
		doRetrieveMatchingFiles(fullPattern, rootDir, result);
		return result;
	}

调用递归方法:
doRetrieveMatchingFiles
	protected void doRetrieveMatchingFiles(String fullPattern, File dir, Set<File> result) throws IOException {
		if (logger.isDebugEnabled()) {
			logger.debug("Searching directory [" + dir.getAbsolutePath() +
					"] for files matching pattern [" + fullPattern + "]");
		}
		File[] dirContents = dir.listFiles();
		if (dirContents == null) {
			if (logger.isWarnEnabled()) {
				logger.warn("Could not retrieve contents of directory [" + dir.getAbsolutePath() + "]");
			}
			return;
		}
		for (File content : dirContents) {
			String currPath = StringUtils.replace(content.getAbsolutePath(), File.separator, "/");
			if (content.isDirectory() && getPathMatcher().matchStart(fullPattern, currPath + "/")) {
				if (!content.canRead()) {
					if (logger.isDebugEnabled()) {
						logger.debug("Skipping subdirectory [" + dir.getAbsolutePath() +
								"] because the application is not allowed to read the directory");
					}
				}
				else {
					doRetrieveMatchingFiles(fullPattern, content, result);
				}
			}
			if (getPathMatcher().match(fullPattern, currPath)) {
				result.add(content);
			}
		}
	}
分享到:
评论

相关推荐

    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 . . . . ...

    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