??@RequestMapping
源码解析主要分为两个阶段:
??① @RequestMapping
注释的方法扫描注册。
??② 请求匹配@RequestMapping
注释的方法。
??本文针对第②
阶段从源码角度进行解析,关于第①
阶段请参照《Spring 注解面面通 之 @RequestMapping 注册处理方法源码解析》。
???**注意:**请求匹配@RequestMapping
注释方法的起点是DispatcherServlet.doDispatch(...)
。
??源码流程
??下面列出了源码的调用流程,其中仅涉及主要处理步骤。
??源码解析
??1) DispatcherServlet.doDispatch(...)
方法。
??① 取得请求HttpServletRequest
异步管理器WebAsyncManager
。
??② 确认请求HttpServletRequest
是否为multipart/form-data
类型请求。
??③ 通过请求HttpServletRequest
从DispatcherServlet.properties
提供的默认策略中获取org.springframework.web.servlet.HandlerMapping
列表,通过其取得对应的处理器。
??④ 通过请求HttpServletRequest
从DispatcherServlet.properties
提供的默认策略中获取org.springframework.web.servlet.HandlerAdapter
列表,通过其取得③
中处理器对应的处理器适配器。
??⑤ 当Http方法为GET
、HEAD
时,处理Last-Modified
请求标头。
??⑥ 按照执行链上拦截器的顺序调用其preHandle(...)
方法,此时,若preHandle(...)
返回false
,会按照执行链上拦截器的反顺序调用其afterCompletion(...)
方法。
??⑦ 调用实际的处理器的方法。
??⑧ 若是异步请求,则异步进行处理器处理,DispatcherServlet.doDispatch(...)
返回。
??⑨ 若⑦
中返回的ModelAndView不包括视图,则配置默认视图。
??⑩ 按照执行链上拦截器的反顺序调用其postHandle(...)
方法。
???? 调用DispatcherServlet.processDispatchResult(...)
方法处理最终结果,并在方法最后按照执行链上拦截器的反顺序调用其afterCompletion(...)
方法。
???? 此外,在最外层try { ... } catch (Exception ex) { ... } catch (Throwable err) { ... }
的catch { ... }
中也会后按照执行链上拦截器的反顺序调用其afterCompletion(...)
方法,但仔细查看代码会发现,这种情况发生概率几乎为零。
/*** 分发请求给处理程序.* 处理程序将按照顺序处理Servlet的HandlerMappings.* HandlerAdapter将通过查询Servlet已配置的HandlerAdapter来获取,以找到第一个支持handler类的HandlerAdapter.* 所有的HTTP方法都由这个方法处理.* 由HandlerAdapter或处理程序自己决定哪些方法是可接受的.* @param request 当前请求实例.* @param response 当前响应实例.* @throws Exception .*/
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;// 处理器执行链.HandlerExecutionChain mappedHandler = null;boolean multipartRequestParsed = false;WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);try {
ModelAndView mv = null;Exception dispatchException = null;try {
// 确认是否multipart/form-data请求.processedRequest = checkMultipart(request);multipartRequestParsed = (processedRequest != request);// 获得当前请求的处理器.mappedHandler = getHandler(processedRequest);if (mappedHandler == null) {
noHandlerFound(processedRequest, response);return;}// 获取当前请求的处理器适配器.HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());// 处理last-modified请求头.String method = request.getMethod();boolean isGet = "GET".equals(method);if (isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());if (logger.isDebugEnabled()) {
logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);}if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;}}// 调用拦截器的applyPreHandle方法.if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;}// 实际调用处理器方法处理请求.mv = ha.handle(processedRequest, response, mappedHandler.getHandler());if (asyncManager.isConcurrentHandlingStarted()) {
return;}// 处理默认视图.applyDefaultViewName(processedRequest, mv);// 调用拦截器的applyPostHandle方法.mappedHandler.applyPostHandle(processedRequest, response, mv);}catch (Exception ex) {
dispatchException = ex;}catch (Throwable err) {
// 从4.3开始,同时会处理从handler方法抛出的错误,使它们可以用于@ExceptionHandler方法和其他场景.dispatchException = new NestedServletException("Handler dispatch failed", err);}// 处理转发结果.processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);}catch (Exception ex) {
// 调用拦截器的triggerAfterCompletion方法.triggerAfterCompletion(processedRequest, response, mappedHandler, ex);}catch (Throwable err) {
// 调用拦截器的triggerAfterCompletion方法.triggerAfterCompletion(processedRequest, response, mappedHandler,new NestedServletException("Handler processing failed", err));}finally {
if (asyncManager.isConcurrentHandlingStarted()) {
// 代替postHandle和afterCompletion.if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);}}else {
// 清除multipart/form-data请求使用的所有资源.if (multipartRequestParsed) {
cleanupMultipart(processedRequest);}}}
}
???2) DispatcherServlet.getHandler(...)
方法。
??遍历DispatcherServlet
的映射处理器handlerMappings
,默认情况下,在DispatcherServlet.properties
内定义,查找HandlerExecutionChain
。
/*** 返回处理请求的HandlerExecutionChain.* 按顺序的所有映射.* @param request 当前请求实例.* @return HandlerExecutionChain.*/
@Nullable
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
if (this.handlerMappings != null) {
for (HandlerMapping hm : this.handlerMappings) {
if (logger.isTraceEnabled()) {
logger.trace("Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");}// 根据Request获取处理器.HandlerExecutionChain handler = hm.getHandler(request);if (handler != null) {
return handler;}}}return null;
}
??3) AbstractHandlerMapping.getHandler(...)
方法。
???① 查找当前请求的最佳匹配处理程序方法。
??② 若未匹配到处理器,使用默认处理器。
???③ 若处理器是String
类型,则作为Bean
名称从ApplicationContext
获取Bean
。
??④ 匹配的处理器转换为HandlerExecutionChain
。
??⑤ 若请求是有效的CORS
请求,则设置相关配置信息。
/*** 查找给定请求的处理程序,如果找不到特定的处理程序,则返回到默认处理程序.* @param request 当前请求实例.* @return 相应的处理程序实例,或默认处理程序.*/
@Override
@Nullable
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
// 查找当前请求的最佳匹配处理程序方法.Object handler = getHandlerInternal(request);// 若不存在,使用默认处理器.if (handler == null) {
handler = getDefaultHandler();}if (handler == null) {
return null;}// Bean名称或解析处理程序.if (handler instanceof String) {
String handlerName = (String) handler;handler = obtainApplicationContext().getBean(handlerName);}// handler转换为HandlerExecutionChain.HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);// 请求是有效的CORS请求.if (CorsUtils.isCorsRequest(request)) {
CorsConfiguration globalConfig = this.globalCorsConfigSource.getCorsConfiguration(request);CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);executionChain = getCorsHandlerExecutionChain(request, executionChain, config);}return executionChain;
}
??4) AbstractHandlerMethodMapping.getHandlerInternal(...)
方法。
??① 通过UrlPathHelper
,从HttpServletRequest
中获取查找路径。
??② 获取mappingRegistry
的锁信息。
??③ 查找当前请求的最佳匹配处理方法。
??④ 释放mappingRegistry
的锁信息。
/*** 查找给定请求的处理程序方法.*/
@Override
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
// 获取请求的查找路径.String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);if (logger.isDebugEnabled()) {
logger.debug("Looking up handler method for path " + lookupPath);}// 取得映射注册器的读取锁.this.mappingRegistry.acquireReadLock();try {
// 查找当前请求的最佳匹配处理程序方法.HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);if (logger.isDebugEnabled()) {
if (handlerMethod != null) {
logger.debug("Returning handler method [" + handlerMethod + "]");}else {
logger.debug("Did not find handler method for [" + lookupPath + "]");}}return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);}finally {
this.mappingRegistry.releaseReadLock();}
}
??5) AbstractHandlerMethodMapping.lookupHandlerMethod(...)
方法。
??① 直接从mappingRegistry
中完全匹配查找lookupPath
。
??② 若无可完全匹配内容,则需对所有映射进行匹配。
??③ 取得比较器,在查找的匹配结果里得到最优匹配的处理方法。
/*** 查找当前请求的最佳匹配处理程序方法.* 如果找到多个匹配项,则选择最佳匹配项.* @param lookupPath 在当前Servlet映射中映射查找路径.* @param request 当前请求实例.* @return 最佳匹配的处理程序方法,如果不匹配,返回null.*/
@Nullable
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()) {
// 别无选择,只能浏览所有映射.addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request);}if (!matches.isEmpty()) {
// 获取匹配比较器.Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));matches.sort(comparator);if (logger.isTraceEnabled()) {
logger.trace("Found " + matches.size() + " matching mapping(s) for [" + lookupPath + "] : " + matches);}// 选择优先级最高的匹配.Match bestMatch = matches.get(0);if (matches.size() > 1) {
if (CorsUtils.isPreFlightRequest(request)) {
return PREFLIGHT_AMBIGUOUS_MATCH;}Match secondBestMatch = matches.get(1);if (comparator.compare(bestMatch, secondBestMatch) == 0) {
Method m1 = bestMatch.handlerMethod.getMethod();Method m2 = secondBestMatch.handlerMethod.getMethod();throw new IllegalStateException("Ambiguous handler methods mapped for HTTP path '" +request.getRequestURL() + "': {" + m1 + ", " + m2 + "}");}}// 在找到匹配映射时调用.handleMatch(bestMatch.mapping, lookupPath, request);return bestMatch.handlerMethod;}else {
return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);}
}
??6) RequestMappingInfoHandlerMapping.getMappingComparator(...)
方法。
??通过Java 8
的Lambda
表达式创建RequestMappingInfo
的比较器Comparator
。
/*** 提供一个比较器来排序与请求匹配的RequestMappingInfos.*/
@Override
protected Comparator<RequestMappingInfo> getMappingComparator(final HttpServletRequest request) {
return (info1, info2) -> info1.compareTo(info2, request);
}
??7) RequestMappingInfo.compareTo(...)
方法。
??① 若Http请求方法是HEAD
,则首先进行基于@RequestMapping.method
的匹配,若匹配通过,不进行额外匹配。
??② 进行基于@RequestMapping.value
或@RequestMapping.path
的匹配。
??③ 进行基于@RequestMapping.params
的匹配。
??④ 进行基于@RequestMapping.headers
的匹配。
???⑤ 进行基于@RequestMapping.consumes
的匹配。
??⑥ 进行基于@RequestMapping.produces
的匹配。
??⑦ 进行基于@RequestMapping.method
的匹配。
??⑧ 进行基于自定义条件比较器的匹配.
/*** 将当前RequestMappingInfo(即当前实例)与请求上下文中的另一个RequestMappingInfo进行比较.* 注意: 假设这两个实例都是通过getMatchingCondition(HttpServletRequest)获得的,以确保它们具有与当前请求相关的内容的条件.*/
@Override
public int compareTo(RequestMappingInfo other, HttpServletRequest request) {
int result;// 自动与显式HTTP头映射.if (HttpMethod.HEAD.matches(request.getMethod())) {
result = this.methodsCondition.compareTo(other.getMethodsCondition(), request);if (result != 0) {
return result;}}// RequestMapping.path匹配.result = this.patternsCondition.compareTo(other.getPatternsCondition(), request);if (result != 0) {
return result;}// RequestMapping.params匹配.result = this.paramsCondition.compareTo(other.getParamsCondition(), request);if (result != 0) {
return result;}// RequestMapping.headers匹配.result = this.headersCondition.compareTo(other.getHeadersCondition(), request);if (result != 0) {
return result;}// RequestMapping.consumes匹配.result = this.consumesCondition.compareTo(other.getConsumesCondition(), request);if (result != 0) {
return result;}// RequestMapping.produces匹配.result = this.producesCondition.compareTo(other.getProducesCondition(), request);if (result != 0) {
return result;}// RequestMapping.method匹配.// 隐式(无方法)与显式HTTP方法映射.result = this.methodsCondition.compareTo(other.getMethodsCondition(), request);if (result != 0) {
return result;}// 自定义条件处理器匹配.result = this.customConditionHolder.compareTo(other.customConditionHolder, request);if (result != 0) {
return result;}return 0;
}
??8) RequestMappingInfoHandlerMapping.handleMatch(...)
方法。
/*** 暴露URI模板变量、矩阵变量和可生成的媒体类型.*/
@Override
protected void handleMatch(RequestMappingInfo info, String lookupPath, HttpServletRequest request) {
super.handleMatch(info, lookupPath, request);String bestPattern;Map<String, String> uriVariables;Map<String, String> decodedUriVariables;Set<String> patterns = info.getPatternsCondition().getPatterns();// 若不存在匹配模式,则均设置为空.if (patterns.isEmpty()) {
bestPattern = lookupPath;uriVariables = Collections.emptyMap();decodedUriVariables = Collections.emptyMap();}else {
bestPattern = patterns.iterator().next();// 解析URI模板变量.uriVariables = getPathMatcher().extractUriTemplateVariables(bestPattern, lookupPath);// 对URI模板变量进行解码.decodedUriVariables = getUrlPathHelper().decodePathVariables(request, uriVariables);}// 设置匹配模式到HttpServletRequest的BEST_MATCHING_PATTERN_ATTRIBUTE.request.setAttribute(BEST_MATCHING_PATTERN_ATTRIBUTE, bestPattern);// 设置URI模板变量到HttpServletRequest的HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE.request.setAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, decodedUriVariables);// 处理矩阵变量.if (isMatrixVariableContentAvailable()) {
// 提取矩阵变量.Map<String, MultiValueMap<String, String>> matrixVars = extractMatrixVariables(request, uriVariables);// 设置矩阵变量到HttpServletRequest的HandlerMapping.MATRIX_VARIABLES_ATTRIBUTE.request.setAttribute(HandlerMapping.MATRIX_VARIABLES_ATTRIBUTE, matrixVars);}// 处理可生成的媒体类型.if (!info.getProducesCondition().getProducibleMediaTypes().isEmpty()) {
// 获取可生成的媒体类型.Set<MediaType> mediaTypes = info.getProducesCondition().getProducibleMediaTypes();// 设置可生成媒体类型到HttpServletRequest的PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE.request.setAttribute(PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE, mediaTypes);}
}
??总结
??本文分析了请求匹配处理方法的流程,其中仅对重要步骤源码进行了分析。整个过程中如何进行条件匹配
部分内容尚未分析,会在后续博文中解析。
??源码解析基于spring-framework-5.0.5.RELEASE
版本源码。
??若文中存在错误和不足,欢迎指正!