WebFlux 路由匹配算法详解
概述
WebFlux 的路由匹配算法是其核心功能之一,负责将 HTTP 请求映射到对应的处理器方法。WebFlux 支持两种主要的路由方式:基于注解的 @RequestMapping 和基于函数的 RouterFunction。本文深入剖析 WebFlux 路由匹配算法的设计原理、实现机制和优化策略。
路由算法架构
1. 整体路由架构
2. 路由匹配流程
注解路由匹配算法
1. RequestMappingHandlerMapping 架构
2. 映射注册过程
public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMapping {
private final MappingRegistry mappingRegistry = new MappingRegistry();
@Override
protected void initHandlerMethods() {
// 1. 获取所有候选Bean
String[] beanNames = obtainApplicationContext().getBeanNamesForType(Object.class);
for (String beanName : beanNames) {
// 2. 检查是否是Handler
if (!isHandler(getApplicationContext().getType(beanName))) {
continue;
}
// 3. 处理方法级别的映射
processHandlerMethod(beanName);
}
// 4. 初始化处理器方法
initializeHandlerMethods();
}
private void processHandlerMethod(String beanName) {
Class<?> handlerType = obtainApplicationContext().getType(beanName);
Class<?> userType = ClassUtils.getUserClass(handlerType);
// 获取所有方法
Method[] methods = MethodIntrospector.selectMethods(userType,
(MethodIntrospector.MetadataLookup<RequestMappingInfo>) method -> {
try {
// 为每个方法创建RequestMappingInfo
return getMappingForMethod(method, userType);
} catch (Throwable ex) {
throw new IllegalStateException("Invalid mapping on handler class [" +
userType.getName() + "]: " + method, ex);
}
});
// 注册映射关系
methods.forEach(method -> {
RequestMappingInfo mapping = methods.get(method);
registerHandlerMethod(beanName, method, mapping);
});
}
@Override
protected boolean isHandler(Class<?> beanType) {
// 检查是否有@Controller或@RequestMapping注解
return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||
AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
}
}
3. RequestMappingInfo 构建算法
public class RequestMappingInfo {
private final PathPatternsRequestCondition patternsCondition;
private final RequestMethodsRequestCondition methodsCondition;
private final ParamsRequestCondition paramsCondition;
private final HeadersRequestCondition headersCondition;
private final ConsumesRequestCondition consumesCondition;
private final ProducesRequestCondition producesCondition;
public static Builder paths(String... paths) {
return new DefaultBuilder(paths);
}
public RequestMappingInfo combine(RequestMappingInfo other) {
// 组合两个RequestMappingInfo(用于类级别和方法级别的组合)
return new RequestMappingInfo(
this.patternsCondition.combine(other.patternsCondition),
this.methodsCondition.combine(other.methodsCondition),
this.paramsCondition.combine(other.paramsCondition),
this.headersCondition.combine(other.headersCondition),
this.consumesCondition.combine(other.consumesCondition),
this.producesCondition.combine(other.producesCondition)
);
}
}
4. 路径匹配算法
5. AntPathMatcher 实现
public class AntPathMatcher implements PathMatcher {
private static final Pattern VARIABLE_PATTERN = Pattern.compile("\\{[^/]+?\\}");
@Override
public boolean match(String pattern, String path) {
return doMatch(pattern, path, true, null);
}
protected boolean doMatch(String pattern, String path, boolean fullMatch,
@Nullable Map<String, String> uriTemplateVariables) {
if (path.startsWith("/") != pattern.startsWith("/")) {
return false;
}
String[] pattDirs = tokenizePattern(pattern);
String[] pathDirs = tokenizePath(path);
int pattIdxStart = 0;
int pattIdxEnd = pattDirs.length - 1;
int pathIdxStart = 0;
int pathIdxEnd = pathDirs.length - 1;
// 匹配路径段
while (pattIdxStart <= pattIdxEnd && pathIdxStart <= pathIdxEnd) {
String pattDir = pattDirs[pattIdxStart];
if ("**".equals(pattDir)) {
break;
}
if (!matchStrings(pattDir, pathDirs[pathIdxStart], uriTemplateVariables)) {
return false;
}
pattIdxStart++;
pathIdxStart++;
}
if (pathIdxStart > pathIdxEnd) {
// 路径已经匹配完毕
if (pattIdxStart > pattIdxEnd) {
return (pattern.endsWith("/") == path.endsWith("/"));
}
if (!fullMatch) {
return true;
}
if (pattIdxStart == pattIdxEnd && pattDirs[pattIdxStart].equals("*") &&
path.endsWith("/")) {
return true;
}
for (int i = pattIdxStart; i <= pattIdxEnd; i++) {
if (!pattDirs[i].equals("**")) {
return false;
}
}
return true;
} else if (pattIdxStart > pattIdxEnd) {
// 模式已经匹配完毕,但路径还有剩余
return false;
} else if (!fullMatch && "**".equals(pattDirs[pattIdxStart])) {
return true;
}
// 处理**通配符
while (pattIdxStart <= pattIdxEnd && pathIdxStart <= pathIdxEnd) {
String pattDir = pattDirs[pattIdxEnd];
if (pattDir.startsWith("**")) {
break;
}
if (!matchStrings(pattDir, pathDirs[pathIdxEnd], uriTemplateVariables)) {
return false;
}
pattIdxEnd--;
pathIdxEnd--;
}
if (pathIdxStart > pathIdxEnd) {
// 路径已经匹配完毕
for (int i = pattIdxStart; i <= pattIdxEnd; i++) {
if (!pattDirs[i].equals("**")) {
return false;
}
}
return true;
}
return true;
}
private boolean matchStrings(String pattern, String str,
@Nullable Map<String, String> uriTemplateVariables) {
// 处理路径变量
if (pattern.startsWith("{") && pattern.endsWith("}")) {
if (uriTemplateVariables != null) {
String variableName = pattern.substring(1, pattern.length() - 1);
uriTemplateVariables.put(variableName, str);
}
return true;
}
return pattern.equals(str);
}
}
函数式路由匹配算法
1. RouterFunction 架构
2. RouterFunction 构建过程
public class RouterFunctions {
public static <T extends ServerResponse> RouterFunction<T> route() {
return new RouterFunctionBuilder<>();
}
public static class RouterFunctionBuilder<T extends ServerResponse> {
private final List<RouterFunction<T>> routerFunctions = new ArrayList<>();
public RouterFunctionBuilder<T> GET(String pattern,
HandlerFunction<T> handlerFunction) {
return route(RequestPredicates.GET(pattern), handlerFunction);
}
public RouterFunctionBuilder<T> POST(String pattern,
HandlerFunction<T> handlerFunction) {
return route(RequestPredicates.POST(pattern), handlerFunction);
}
public RouterFunctionBuilder<T> route(RequestPredicate predicate,
HandlerFunction<T> handlerFunction) {
this.routerFunctions.add(new DefaultRouterFunction<>(predicate, handlerFunction));
return this;
}
public RouterFunction<T> build() {
return routerFunctions.stream()
.reduce(RouterFunction::andOther)
.orElseThrow(() -> new IllegalStateException("No routes defined"));
}
}
}
3. RequestPredicate 实现
public interface RequestPredicate {
/**
* 评估请求是否匹配谓词条件
*/
boolean test(ServerWebExchange exchange);
/**
* 组合两个谓词(AND关系)
*/
default RequestPredicate and(RequestPredicate other) {
return new AndRequestPredicate(this, other);
}
/**
* 组合两个谓词(OR关系)
*/
default RequestPredicate or(RequestPredicate other) {
return new OrRequestPredicate(this, other);
}
/**
* 取反谓词
*/
default RequestPredicate negate() {
return new NegateRequestPredicate(this);
}
}
4. 路径谓词实现
public class PathPatternPredicate implements RequestPredicate {
private final PathPattern pattern;
public PathPatternPredicate(String pattern) {
this.pattern = PathPatternParser.defaultInstance.parse(pattern);
}
@Override
public boolean test(ServerWebExchange exchange) {
// 1. 获取请求路径
String path = exchange.getRequest().getURI().getPath();
// 2. 进行路径匹配
PathPattern.PathMatchInfo matchInfo = this.pattern.matchAndExtract(path);
if (matchInfo != null) {
// 3. 提取路径变量
Map<String, String> uriVariables = matchInfo.getUriVariables();
// 4. 存储路径变量到exchange属性中
exchange.getAttributes().put(
RouterFunctions.URI_TEMPLATE_VARIABLES_ATTRIBUTE,
uriVariables);
return true;
}
return false;
}
}
5. 组合谓词算法
public class AndRequestPredicate implements RequestPredicate {
private final RequestPredicate left;
private final RequestPredicate right;
@Override
public boolean test(ServerWebExchange exchange) {
// 短路求值:如果左边为false,直接返回false
return this.left.test(exchange) && this.right.test(exchange);
}
}
public class OrRequestPredicate implements RequestPredicate {
private final RequestPredicate left;
private final RequestPredicate right;
@Override
public boolean test(ServerWebExchange exchange) {
// 短路求值:如果左边为true,直接返回true
return this.left.test(exchange) || this.right.test(exchange);
}
}
路由优先级算法
1. 匹配优先级规则
2. 匹配比较器实现
public class RequestMappingInfoComparator implements Comparator<RequestMappingInfo> {
@Override
public int compare(RequestMappingInfo info1, RequestMappingInfo info2) {
int result;
// 1. 比较路径模式(更具体的优先)
result = info1.getPatternsCondition().compareTo(info2.getPatternsCondition());
if (result != 0) {
return result;
}
// 2. 比较HTTP方法(更具体的优先)
result = info1.getMethodsCondition().compareTo(info2.getMethodsCondition());
if (result != 0) {
return result;
}
// 3. 比较参数条件
result = info1.getParamsCondition().compareTo(info2.getParamsCondition());
if (result != 0) {
return result;
}
// 4. 比较头信息条件
result = info1.getHeadersCondition().compareTo(info2.getHeadersCondition());
if (result != 0) {
return result;
}
// 5. 比较consumes条件
result = info1.getConsumesCondition().compareTo(info2.getConsumesCondition());
if (result != 0) {
return result;
}
// 6. 比较produces条件
result = info1.getProducesCondition().compareTo(info2.getProducesCondition());
if (result != 0) {
return result;
}
return 0;
}
}
3. 路径模式比较算法
public class PatternsRequestCondition extends AbstractRequestCondition<PatternsRequestCondition> {
private final List<PathPattern> patterns;
@Override
protected int compareTo(PatternsRequestCondition other) {
// 比较两个路径模式的精确度
PathPattern pattern1 = this.patterns.get(0);
PathPattern pattern2 = other.patterns.get(0);
// 1. 计算路径变量数量(越少越具体)
int vars1 = pattern1.getPatternString().split("\\{").length - 1;
int vars2 = pattern2.getPatternString().split("\\{").length - 1;
int result = Integer.compare(vars1, vars2);
if (result != 0) {
return result;
}
// 2. 计算通配符数量(越少越具体)
int wildcards1 = StringUtils.countOccurrencesOf(pattern1.getPatternString(), "*");
int wildcards2 = StringUtils.countOccurrencesOf(pattern2.getPatternString(), "*");
result = Integer.compare(wildcards1, wildcards2);
if (result != 0) {
return result;
}
// 3. 计算路径段数量(越多越具体)
int length1 = pattern1.getPatternString().split("/").length;
int length2 = pattern2.getPatternString().split("/").length;
result = Integer.compare(length2, length1);
if (result != 0) {
return result;
}
// 4. 按字母顺序比较(确保确定性)
return pattern1.getPatternString().compareTo(pattern2.getPatternString());
}
}
路径变量提取算法
1. 路径变量解析
2. 路径变量提取实现
public class PathPattern {
private final List<PathElement> pathElements;
@Nullable
public PathMatchInfo matchAndExtract(String path) {
MatchingContext matchingContext = new MatchingContext(path, true);
// 1. 尝试匹配路径
if (matches(0, matchingContext)) {
// 2. 提取路径变量
Map<String, String> uriVariables = new LinkedHashMap<>();
extractUriVariables(0, matchingContext, uriVariables);
// 3. 提取矩阵变量(如果有)
Map<String, MultiValueMap<String, String>> matrixVariables = null;
if (!this.matrixVariableNames.isEmpty()) {
matrixVariables = new LinkedHashMap<>();
extractMatrixVariables(0, matchingContext, matrixVariables);
}
return new PathMatchInfo(uriVariables, matrixVariables);
}
return null;
}
private boolean extractUriVariables(int pathIndex, MatchingContext matchingContext,
Map<String, String> uriVariables) {
// 遍历路径元素,提取变量
for (int i = pathIndex; i < this.pathElements.size(); i++) {
PathElement element = this.pathElements.get(i);
if (element instanceof CaptureVariablePathElement) {
// 处理路径变量
CaptureVariablePathElement captureElement = (CaptureVariablePathElement) element;
String variableName = captureElement.getVariableName();
String variableValue = matchingContext.getCapturedVariable(variableName);
uriVariables.put(variableName, variableValue);
}
}
return true;
}
}
3. 类型转换机制
public class PathVariableMethodArgumentResolver implements HandlerMethodArgumentResolver {
@Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.hasParameterAnnotation(PathVariable.class);
}
@Override
public Mono<Object> resolveArgument(MethodParameter parameter, ServerWebExchange exchange) {
// 1. 获取路径变量注解
PathVariable pathVariable = parameter.getParameterAnnotation(PathVariable.class);
String variableName = pathVariable.value().isEmpty() ?
parameter.getParameterName() : pathVariable.value();
// 2. 从exchange属性中获取路径变量
Map<String, String> uriTemplateVariables = exchange.getAttribute(
HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE);
if (uriTemplateVariables == null || !uriTemplateVariables.containsKey(variableName)) {
return Mono.error(new IllegalStateException(
"Missing path variable '" + variableName + "' for method parameter " + parameter));
}
String variableValue = uriTemplateVariables.get(variableName);
// 3. 类型转换
return convertVariableValue(variableValue, parameter);
}
private Mono<Object> convertVariableValue(String value, MethodParameter parameter) {
Class<?> parameterType = parameter.getParameterType();
// 基本类型转换
if (parameterType == String.class) {
return Mono.just(value);
} else if (parameterType == Integer.class || parameterType == int.class) {
return Mono.just(Integer.parseInt(value));
} else if (parameterType == Long.class || parameterType == long.class) {
return Mono.just(Long.parseLong(value));
} else if (parameterType == Boolean.class || parameterType == boolean.class) {
return Mono.just(Boolean.parseBoolean(value));
}
// 使用ConversionService进行复杂类型转换
return Mono.just(conversionService.convert(value, parameterType));
}
}
性能优化算法
1. 路由缓存机制
2. 匹配缓存实现
public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMapping {
// 路径匹配缓存
private final Map<String, List<RequestMappingInfo>> pathLookup = new ConcurrentHashMap<>();
// HandlerMethod缓存
private final Map<RequestMappingInfo, HandlerMethod> handlerMethods = new ConcurrentHashMap<>();
@Override
protected HandlerMethod getHandlerInternal(ServerWebExchange exchange) throws Exception {
String lookupPath = initLookupPath(exchange);
// 1. 检查HandlerMethod缓存
HandlerMethod handlerMethod = this.handlerMethodLookup.get(lookupPath);
if (handlerMethod != null) {
return handlerMethod;
}
// 2. 执行匹配算法
handlerMethod = lookupHandlerMethod(lookupPath, exchange);
// 3. 缓存结果
if (handlerMethod != null) {
this.handlerMethodLookup.put(lookupPath, handlerMethod);
}
return handlerMethod;
}
}
3. 路径模式预编译
public class PathPatternParser {
private final Map<String, PathPattern> patternCache = new ConcurrentHashMap<>();
public PathPattern parse(String pattern) {
// 1. 检查缓存
PathPattern pathPattern = this.patternCache.get(pattern);
if (pathPattern != null) {
return pathPattern;
}
// 2. 解析路径模式
pathPattern = doParse(pattern);
// 3. 缓存解析结果
this.patternCache.put(pattern, pathPattern);
return pathPattern;
}
private PathPattern doParse(String pattern) {
// 将路径模式解析为PathElement列表
List<PathElement> pathElements = new ArrayList<>();
String[] pathSegments = pattern.split("/");
for (String segment : pathSegments) {
if (segment.isEmpty()) {
continue;
}
if (segment.startsWith("{") && segment.endsWith("}")) {
// 路径变量
String variableName = segment.substring(1, segment.length() - 1);
pathElements.add(new CaptureVariablePathElement(variableName));
} else if (segment.equals("*")) {
// 单级通配符
pathElements.add(new WildcardPathElement());
} else if (segment.equals("**")) {
// 多级通配符
pathElements.add(new WildcardTheRestPathElement());
} else {
// 普通路径段
pathElements.add(new LiteralPathElement(segment));
}
}
return new PathPattern(pattern, pathElements);
}
}
路由冲突检测算法
1. 冲突检测机制
2. 冲突检测实现
public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMapping {
@Override
protected void registerHandlerMethod(Object handler, Method method, RequestMappingInfo mapping) {
// 1. 检查是否存在冲突
checkForConflicts(mapping);
// 2. 注册映射关系
super.registerHandlerMethod(handler, method, mapping);
}
private void checkForConflicts(RequestMappingInfo newMapping) {
// 获取所有现有映射
Set<RequestMappingInfo> existingMappings = this.mappingRegistry.getMappings().keySet();
for (RequestMappingInfo existingMapping : existingMappings) {
// 检查路径模式是否相同
if (hasSamePattern(newMapping, existingMapping)) {
// 检查谓词条件是否重叠
if (hasOverlappingConditions(newMapping, existingMapping)) {
// 报告冲突
reportMappingConflict(newMapping, existingMapping);
}
}
}
}
private boolean hasSamePattern(RequestMappingInfo mapping1, RequestMappingInfo mapping2) {
Set<String> patterns1 = mapping1.getPatternsCondition().getPatterns();
Set<String> patterns2 = mapping2.getPatternsCondition().getPatterns();
return !Collections.disjoint(patterns1, patterns2);
}
private boolean hasOverlappingConditions(RequestMappingInfo mapping1, RequestMappingInfo mapping2) {
// 检查HTTP方法
RequestMethodsRequestCondition methods1 = mapping1.getMethodsCondition();
RequestMethodsRequestCondition methods2 = mapping2.getMethodsCondition();
if (!methods1.getMethods().isEmpty() && !methods2.getMethods().isEmpty()) {
Set<RequestMethod> intersection = new HashSet<>(methods1.getMethods());
intersection.retainAll(methods2.getMethods());
if (intersection.isEmpty()) {
return false; // 方法不重叠
}
}
// 检查其他条件...
return true; // 条件重叠,存在冲突
}
}
总结
WebFlux 的路由匹配算法通过以下机制实现高效、准确的路由:
- 多层次匹配:支持路径、方法、参数、头信息等多维度匹配
- 优先级排序:通过精确度评分选择最佳匹配
- 缓存优化:预编译和缓存提高匹配性能
- 冲突检测:及时发现和报告路由冲突
- 类型安全:支持路径变量的类型转换和验证
- 扩展性:支持自定义谓词和匹配条件
理解这些算法对于:
- 优化路由性能
- 避免路由冲突
- 设计合理的URL结构
- 调试路由问题
具有重要的实践意义。
1272

被折叠的 条评论
为什么被折叠?



