背景
最近要做一个URL到权限的控制,需要根据实际的URL匹配到配置文件,一般的url好处理,但是对于path parameter 的URL就需要做匹配了,所以研读了一下springmvc的源码,看看是如何做的
-
入口 FrameworkServlet
-
- .doPost(HttpServletRequest request, HttpServletResponse response)
-
DispatcherServlet
-
- .doService
-
- DispatcherServlet.doDispatch
-
-
HandlerExecutionChain mappedHandler =getHandler(processedRequest)
这里有多个handlerMapping,实际用到的是RequestMappingHandlerMappingthis.handlerMappings ={ArrayList@14007} size =7
0={WebMvcEndpointHandlerMapping@13963}
1={ControllerEndpointHandlerMapping@14199}
2={RequestMappingHandlerMapping@9698}
3={BeanNameUrlHandlerMapping@14200}
4= {RouterFunctionMapping@14201}
5={SimpleUrlHandlerMapping@14202}
6={WelcomePageHandlerMapping@14203}
-
-
AbstractHandlerMethodMapping
从这个mapping 中获取RequestMappingHandlerMapping -
-
HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request)
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception { List<Match> matches = new ArrayList<>(); List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath); if (directPathMatches != null) { addMatchingMappings(directPathMatches, matches, request); } if (matches.isEmpty()) { // No choice but to go through all mappings... addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request); }
-
这段代码有意思,先去根据url 去map中找RequestMappingInfo (封装了URL匹配相关信息) ,然后去做URL匹配
-
-
MappingRegistry 保存了所有的配置
mappingLookup 保存了RequestMappingInfo 和 HandlerMethod 的映射
MultiValueMap<String, T> urlLookup 保存了路径和方法的映射
-
-
所有的配置信息封装在 RequestMappingInfo
public RequestMappingInfo getMatchingCondition(HttpServletRequest request) { RequestMethodsRequestCondition methods = this.methodsCondition.getMatchingCondition(request); if (methods == null) { return null; } ParamsRequestCondition params = this.paramsCondition.getMatchingCondition(request); if (params == null) { return null; } HeadersRequestCondition headers = this.headersCondition.getMatchingCondition(request); if (headers == null) { return null; } ConsumesRequestCondition consumes = this.consumesCondition.getMatchingCondition(request); if (consumes == null) { return null; } ProducesRequestCondition produces = this.producesCondition.getMatchingCondition(request); if (produces == null) { return null; } PatternsRequestCondition patterns = this.patternsCondition.getMatchingCondition(request); if (patterns == null) { return null; } RequestConditionHolder custom = this.customConditionHolder.getMatchingCondition(request); if (custom == null) { return null; } return new RequestMappingInfo(this.name, patterns, methods, params, headers, consumes, produces, custom.getCondition()); }
找到PatternsRequestCondition ,用来做和url做模式匹配
-
PatternsRequestCondition
this.pathMatcher = pathMatcher != null ? pathMatcher : new AntPathMatcher();
this.pathMatcher.match("/Task/GetTaskById/{taskid}", "/Task/GetTaskById/123")
这里实际上是spring 的AntPathMatcher 类,直接调用即可匹配带参数的URL
总结
springMVC 做URL匹配,实际上分两步,1,用url去map中找List directPathMatches
2, 遍历List directPathMatches,逐个做pathMatcher