spring 解析通配符

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

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

先看一个小例子:
Java代码 
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(); 
        } 
    } 


输出结果:
Java代码 
applicationContext.xml 
logback.xml 
menu_my.xml 

是不是很简单?
只要调用PathMatchingResourcePatternResolver的getResources方法就可以实现我们想要的功能。
下面深入研究一下spring的源码PathMatchingResourcePatternResolver:
1、getResources方法
Java代码 
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方法
Java代码 
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
Java代码 
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:
Java代码 
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

Java代码 
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
Java代码 
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); 
        } 
    } 

 

本文出自“goodscript”
 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值