美文网首页
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