antpathmatcher源码实现过程详细解释
时间: 2023-07-30 13:12:18 浏览: 60
AntPathMatcher 的源码实现过程可以分为以下几个步骤:
1. 将模式与路径分割成多个部分,以便逐个进行匹配。
2. 逐个比较模式与路径的每个部分,如果匹配成功,则继续匹配下一个部分,否则返回匹配失败。
3. 如果遇到通配符 `*`,则需要进行特殊处理。当模式中的通配符为 `*` 时,可以匹配任意字符(除了路径分隔符 `/`)。当模式中的通配符为 `**` 时,可以匹配任意路径,包括路径分隔符 `/`。在匹配时,需要分别考虑 `*` 和 `**` 的情况。
4. 如果匹配成功,则可以从路径中提取出匹配模式的部分路径。该部分路径的计算方式与匹配过程相似,但在遇到通配符 `**` 时需要特殊处理。
具体实现细节可以参考 AntPathMatcher 的源码。其中,该类的 `doMatch` 方法实现了路径匹配的核心逻辑,其实现过程符合上述步骤。需要注意的是,该方法是递归调用的,因此需要考虑递归退出条件,以避免出现死循环等问题。
同时,AntPathMatcher 还提供了一些辅助方法,用于判断路径是否以斜杠开头、合并路径等操作。这些方法的实现比较简单,可以直接在源码中查看。
相关问题
AntPathMatcher源码实现* ** ?
AntPathMatcher的匹配算法主要分为两种情况:路径无通配符和路径带通配符。
当路径无通配符时,直接使用字符串比较即可。例如,路径字符串"/hello/world"可以和模式字符串"/hello/world"精确匹配。
当路径带通配符时,需要对模式字符串进行解析,然后逐一比较路径字符串的各个部分。AntPathMatcher支持两种通配符:"*"和"**"。
对于"*"通配符,匹配任意非路径分隔符字符。例如,模式字符串"/hello/*/world"可以匹配路径"/hello/foo/world"、"/hello/bar/world"等。
对于"**"通配符,匹配任意字符,包括路径分隔符。例如,模式字符串"/hello/**/world"可以匹配路径"/hello/foo/bar/world"、"/hello/world"等。
下面是AntPathMatcher的源码实现:
```java
public class AntPathMatcher {
private static final String DEFAULT_PATH_SEPARATOR = "/";
private String pathSeparator = DEFAULT_PATH_SEPARATOR;
public void setPathSeparator(String pathSeparator) {
this.pathSeparator = (pathSeparator != null ? pathSeparator : DEFAULT_PATH_SEPARATOR);
}
public boolean match(String pattern, String path) {
if (StringUtils.isEmpty(pattern) || StringUtils.isEmpty(path)) {
return false;
}
if (path.startsWith(this.pathSeparator) != pattern.startsWith(this.pathSeparator)) {
return false;
}
String[] pattDirs = StringUtils.tokenizeToStringArray(pattern, this.pathSeparator, true, true);
String[] pathDirs = StringUtils.tokenizeToStringArray(path, this.pathSeparator, true, true);
int pattIdxStart = 0;
int pattIdxEnd = pattDirs.length - 1;
int pathIdxStart = 0;
int pathIdxEnd = pathDirs.length - 1;
// Match all elements up to the first **
while (pattIdxStart <= pattIdxEnd && pathIdxStart <= pathIdxEnd) {
String pattDir = pattDirs[pattIdxStart];
if ("**".equals(pattDir)) {
break;
}
if (!matchStrings(pattDir, pathDirs[pathIdxStart])) {
return false;
}
pattIdxStart++;
pathIdxStart++;
}
if (pathIdxStart > pathIdxEnd) {
// Path is exhausted, only match if rest of pattern is * or **'s
if (pattIdxStart > pattIdxEnd) {
return pattern.endsWith(this.pathSeparator) ? path.endsWith(this.pathSeparator) :
!path.endsWith(this.pathSeparator);
}
if (pattIdxStart == pattIdxEnd && "*".equals(pattDirs[pattIdxStart]) && path.endsWith(this.pathSeparator)) {
return true;
}
for (int i = pattIdxStart; i <= pattIdxEnd; i++) {
if (!"**".equals(pattDirs[i])) {
return false;
}
}
return true;
} else if (pattIdxStart > pattIdxEnd) {
// String not exhausted, but pattern is. Failure.
return false;
} else if (!pattern.contains("**")) {
// No more **'s. Check if rest of pattern matches.
return (pattIdxStart == pattIdxEnd && "*".equals(pattDirs[pattIdxStart]) && path.endsWith(this.pathSeparator)) ||
matchStrings(pattDirs, pattIdxStart, pattIdxEnd, pathDirs, pathIdxStart, pathIdxEnd);
}
// Pattern contains '**'
while (pattIdxStart <= pattIdxEnd && pathIdxStart <= pathIdxEnd) {
String pattDir = pattDirs[pattIdxEnd];
if (pattDir.equals("**")) {
break;
}
if (!matchStrings(pattDir, pathDirs[pathIdxEnd])) {
return false;
}
pattIdxEnd--;
pathIdxEnd--;
}
if (pathIdxStart > pathIdxEnd) {
// Path is exhausted
for (int i = pattIdxStart; i <= pattIdxEnd; i++) {
if (!"**".equals(pattDirs[i])) {
return false;
}
}
return true;
}
while (pattIdxStart != pattIdxEnd && pathIdxStart <= pathIdxEnd) {
int patIdxTmp = -1;
for (int i = pattIdxStart + 1; i <= pattIdxEnd; i++) {
if ("**".equals(pattDirs[i])) {
patIdxTmp = i;
break;
}
}
if (patIdxTmp == pattIdxStart + 1) {
// '**/**' situation, so skip one
pattIdxStart++;
continue;
}
// Find the pattern between padIdxStart & padIdxTmp in str between
// strIdxStart & strIdxEnd
int patLength = (patIdxTmp - pattIdxStart - 1);
int strLength = (pathIdxEnd - pathIdxStart + 1);
int foundIdx = -1;
strLoop:
for (int i = 0; i <= strLength - patLength; i++) {
for (int j = 0; j < patLength; j++) {
String subPat = pattDirs[pattIdxStart + j + 1];
String subStr = pathDirs[pathIdxStart + i + j];
if (!matchStrings(subPat, subStr)) {
continue strLoop;
}
}
foundIdx = pathIdxStart + i;
break;
}
if (foundIdx == -1) {
return false;
}
pattIdxStart = patIdxTmp;
pathIdxStart = foundIdx + patLength;
}
for (int i = pattIdxStart; i <= pattIdxEnd; i++) {
if (!"**".equals(pattDirs[i])) {
return false;
}
}
return true;
}
private boolean matchStrings(String pattern, String str) {
return (pattern.equals(str) || pattern.equals("*"));
}
private boolean matchStrings(String[] pattDirs, int pattIdxStart, int pattIdxEnd,
String[] strDirs, int strIdxStart, int strIdxEnd) {
while (pattIdxStart <= pattIdxEnd && strIdxStart <= strIdxEnd) {
String pattDir = pattDirs[pattIdxStart];
String strDir = strDirs[strIdxStart];
if (!matchStrings(pattDir, strDir)) {
return false;
}
pattIdxStart++;
strIdxStart++;
}
return (pattIdxStart > pattIdxEnd && strIdxStart > strIdxEnd);
}
}
```
上面的代码中,match方法用于判断一个路径是否匹配一个模式;matchStrings方法用于判断两个字符串是否匹配。AntPathMatcher中的核心算法比较复杂,需要仔细阅读代码才能理解。
antpathmatcher源码
AntPathMatcher 是 Spring Framework 中的一个路径匹配工具类,用于支持 Ant 风格的路径匹配。该类的源码可以在 Spring Framework 的 GitHub 仓库中找到。
在该类中,主要实现了两个方法:
1. `match(String pattern, String path)`:用于判断给定的路径 `path` 是否匹配指定的模式 `pattern`。该方法会返回一个布尔值,表示是否匹配成功。
2. `extractPathWithinPattern(String pattern, String path)`:用于从给定的路径 `path` 中提取出匹配指定模式 `pattern` 的部分路径。该方法会返回一个字符串,表示提取出的路径。
该类的实现采用了递归的方式进行路径匹配,先将模式与路径分割成多个部分,然后逐个进行匹配。在匹配过程中,如果遇到通配符 `*` 或 `**`,则会进行特殊处理,以实现对 Ant 风格路径的支持。
除了以上两个方法外,AntPathMatcher 还提供了一些其他的辅助方法,用于判断路径是否以斜杠开头、合并路径等操作。可以在源码中进行查看。