美文网首页
ResourceLoader详解(二)

ResourceLoader详解(二)

作者: 北海北_6dc3 | 来源:发表于2019-03-17 23:29 被阅读0次

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<>(16);
        for (Resource rootDirResource : rootDirResources) {
            //供子类复写路径
            rootDirResource = resolveRootDirResource(rootDirResource);
            //获取资源url
            URL rootDirUrl = rootDirResource.getURL();
            //jar包逻辑
            if (ResourceUtils.isJarURL(rootDirUrl) || isJarResource(rootDirResource)) {
                result.addAll(doFindPathMatchingJarResources(rootDirResource, rootDirUrl, subPattern));
            }
            else {
                //非jar包数据
                result.addAll(doFindPathMatchingFileResources(rootDirResource, subPattern));
            }
        }
        return result.toArray(new Resource[0]);
    }

方法思路,获取通配符前缀,根据前缀获取资源路径,
1.jar包资源路径(doFindPathMatchingJarResources)
2.非jar包资源路径(doFindPathMatchingFileResources)

doFindPathMatchingFileResources

非jar包逻辑

        File rootDir;
        try {
            rootDir = rootDirResource.getFile().getAbsoluteFile();
        }
        Set<File> matchingFiles = retrieveMatchingFiles(rootDir, subPattern);
        Set<Resource> result = new LinkedHashSet<>(matchingFiles.size());
        for (File file : matchingFiles) {
            result.add(new FileSystemResource(file));
        }

核心方法,即根据前缀和后缀检索目录

    protected Set<File> retrieveMatchingFiles(File rootDir, String pattern) throws IOException {
         //...是rootDir目录则继续,否返回空。
        //构建匹配全路径
        fullPattern = fullPattern + StringUtils.replace(pattern, File.separator, "/");
        Set<File> result = new LinkedHashSet<>(8);
        doRetrieveMatchingFiles(fullPattern, rootDir, result);
        return result;
    }

核心方法,递归检索与给定模式匹配的文件,将它们添加到给定的结果列表中

    //递归检索与给定模式匹配的文件,将它们添加到给定的结果列表中
    protected void doRetrieveMatchingFiles(String fullPattern, File dir, Set<File> result) throws IOException {
        //获取文件列表并排序
        File[] dirContents = dir.listFiles();
        Arrays.sort(dirContents);
        for (File content : dirContents) {
            String currPath = StringUtils.replace(content.getAbsolutePath(), File.separator, "/");
            //如果匹配为路径,递归计算
            if (content.isDirectory() && getPathMatcher().matchStart(fullPattern, currPath + "/")) {
                    doRetrieveMatchingFiles(fullPattern, content, result);
            }
            //如果匹配为文件
            if (getPathMatcher().match(fullPattern, currPath)) {
                result.add(content);
            }
        }
    }  

其中,getPathMatcher().matchStart(fullPattern, currPath + "/")) ,默认使用的是new AntPathMatcher();

doFindPathMatchingJarResources

通过Ant样式的PathMatcher查找jar文件中与给定位置模式匹配的所有资源

protected Set<Resource> doFindPathMatchingJarResources(Resource rootDirResource, URL rootDirURL, String subPattern)
        throws IOException {

    URLConnection con = rootDirURL.openConnection();
    JarFile jarFile;
    String jarFileUrl;
    String rootEntryPath;
    boolean closeJarFile;

    if (con instanceof JarURLConnection) {
        //传统jar文件解析方案
        JarURLConnection jarCon = (JarURLConnection) con;
        //设置Connection缓存,优先关闭,基于JNLP资源时保留
        ResourceUtils.useCachesIfNecessary(jarCon);
        //返回此链接的jar文件
        jarFile = jarCon.getJarFile();
        //获取jar文件路径字符串
        jarFileUrl = jarCon.getJarFileURL().toExternalForm();
        JarEntry jarEntry = jarCon.getJarEntry();
        //获取跟路径地址
        rootEntryPath = (jarEntry != null ? jarEntry.getName() : "");
        closeJarFile = !jarCon.getUseCaches();
    }
    else {
        // No JarURLConnection -> need to resort to URL file parsing.
        // We'll assume URLs of the format "jar:path!/entry", with the protocol
        // being arbitrary as long as following the entry format.
        // We'll also handle paths with and without leading "file:" prefix.
        String urlFile = rootDirURL.getFile();
        try {
            int separatorIndex = urlFile.indexOf(ResourceUtils.WAR_URL_SEPARATOR);
            if (separatorIndex == -1) {
                separatorIndex = urlFile.indexOf(ResourceUtils.JAR_URL_SEPARATOR);
            }
            if (separatorIndex != -1) {
                jarFileUrl = urlFile.substring(0, separatorIndex);
                rootEntryPath = urlFile.substring(separatorIndex + 2);  // both separators are 2 chars
                //根据jar根目录获取jar文件。
                jarFile = getJarFile(jarFileUrl);
            }
            else {
                jarFile = new JarFile(urlFile);
                jarFileUrl = urlFile;
                rootEntryPath = "";
            }
            closeJarFile = true;
        }
        catch (ZipException ex) {
        }
    }

    try {
        Set<Resource> result = new LinkedHashSet<>(8);
        //遍历jar文件,匹配尾数据路径
        for (Enumeration<JarEntry> entries = jarFile.entries(); entries.hasMoreElements();) {
            JarEntry entry = entries.nextElement();
            String entryPath = entry.getName();
            if (entryPath.startsWith(rootEntryPath)) {
                String relativePath = entryPath.substring(rootEntryPath.length());
                if (getPathMatcher().match(subPattern, relativePath)) {
                    result.add(rootDirResource.createRelative(relativePath));
                }
            }
        }
        return result;
    }
    finally {
        if (closeJarFile) {
            jarFile.close();
        }
    }
}

步骤分为两步:
第一步,读取构建JarFile对象,以便遍历jar包内数据。
方式一:通过JarURLConnection解析
方式二:手动通过分隔符解析,new JarFile
第二步,遍历jar内条目,匹配比较

相关文章

网友评论

      本文标题:ResourceLoader详解(二)

      本文链接:https://www.haomeiwen.com/subject/ylrhpqtx.html