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内条目,匹配比较
网友评论