这一篇,将着手介绍一次请求的处理。用到了 HandlerMapping、HandlerAdapter 知识,若是遇到不是太了解,能够回顾下。java
其实 DispatcherServlet 也只是 Servlet 的一个实现,只不过它集成了 SpringMVC 的几个功能组件(例如视图解析器),对请求及响应进行加工处理,因此探索一个 Servlet 实现,先从它的 service 方法实现开始,来看下 javax.servlet.http.HttpServlet 的实现。web
public abstract class HttpServlet extends GenericServlet { @Override public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException { HttpServletRequest request; HttpServletResponse response; try { request = (HttpServletRequest) req; response = (HttpServletResponse) res; } catch (ClassCastException e) { throw new ServletException("non-HTTP request or response"); } // 向下转型 service(request, response); } protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String method = req.getMethod(); // 根据请求方式调用不一样的 doXxx方法 if (method.equals(METHOD_GET)) { // 固定返回-1,说明缓存机制交由子类扩展 long lastModified = getLastModified(req); if (lastModified == -1) { doGet(req, resp); } else { /** * 缓存机制:首次请求后添加 “Last-Modefied” 的响应头, * 第二次请求发送请求头 If-Modified-Since * 若是服务端内容没有变化,则自动返回 304状态码 */ long ifModifiedSince; try { ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE); } catch (IllegalArgumentException iae) { ifModifiedSince = -1; } if (ifModifiedSince < (lastModified / 1000 * 1000)) { maybeSetLastModified(resp, lastModified); doGet(req, resp); } else { resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED); } } } else if (method.equals(METHOD_HEAD)) { long lastModified = getLastModified(req); maybeSetLastModified(resp, lastModified); doHead(req, resp); } else if (method.equals(METHOD_POST)) { doPost(req, resp); } else if (method.equals(METHOD_PUT)) { doPut(req, resp); } else if (method.equals(METHOD_DELETE)) { doDelete(req, resp); } else if (method.equals(METHOD_OPTIONS)) { doOptions(req, resp); } else if (method.equals(METHOD_TRACE)) { doTrace(req, resp); } else { // 对于不支持请求方式,经过响应流输出错误 String errMsg = lStrings.getString("http.method_not_implemented"); Object[] errArgs = new Object[1]; errArgs[0] = method; errMsg = MessageFormat.format(errMsg, errArgs); resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg); } } }
能够看到 service 就是作了向下转型,调用了 service(HttpServletRequest req, HttpServletResponse resp)。而后在里面根据请求方式,调用不一样的 doXxx 方法。以上属于 servlet-api 自身的实现,接下来看看 SpringMVC 如何在此基础上改造。api
// HttpServletBean是 HttpServlet子类 public abstract class FrameworkServlet extends HttpServletBean implements ApplicationContextAware { // 覆盖 service方法 @Override protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { HttpMethod httpMethod = HttpMethod.resolve(request.getMethod()); // 支持 Patch请求或没有指定请求方法 if (httpMethod == HttpMethod.PATCH || httpMethod == null) { // 无论什么请求,都会调用公共的处理方法 processRequest(request, response); } else { super.service(request, response); } } @Override protected final void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { processRequest(request, response); } @Override protected final void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { processRequest(request, response); } protected final void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 请求开始时间,用于计算请求耗时 long startTime = System.currentTimeMillis(); Throwable failureCause = null; LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext(); // 经过"accept-language"请求头构造 LocaleContext LocaleContext localeContext = buildLocaleContext(request); // 获取当前线程请求的 RequestAttributes RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes(); ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes); // 异步请求管理器 WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request); asyncManager.registerCallableInterceptor( FrameworkServlet.class.getName(), new RequestBindingInterceptor()); // 将 LocaleContext、ServletRequestAttributes与当前线程绑定 initContextHolders(request, localeContext, requestAttributes); try { // 该类定义的抽象方法,子类 DispatcherServlet实现 doService(request, response); } .....// 省略 catch处理 finally{ resetContextHolders(request, previousLocaleContext, previousAttributes); if (requestAttributes != null) { requestAttributes.requestCompleted(); } .....// 省略日志 publishRequestHandledEvent(request, response, startTime, failureCause); } } // 发布 ServletRequestHandledEvent事件 private void publishRequestHandledEvent( HttpServletRequest request, HttpServletResponse response, long startTime, Throwable failureCause) { // 默认为 true if (this.publishEvents) { // 请求耗时 long processingTime = System.currentTimeMillis() - startTime; // 响应码 int statusCode = (responseGetStatusAvailable ? response.getStatus() : -1); // 封装了 请求的 url、remoteAddr、请求方式、sessionId、处理时间、响应码等信息 this.webApplicationContext.publishEvent( new ServletRequestHandledEvent(this, request.getRequestURI(), request.getRemoteAddr(), request.getMethod(), getServletConfig().getServletName(), WebUtils.getSessionId(request), getUsernameForRequest(request), processingTime, failureCause, statusCode)); } } }
除了支持 servlet 自身支持的 7 种请求外,另外支持了 PATCH 方式请求。这里只是列举了 doGet、doPost,其实最终都调用了 processRequest 方法。跨域
processRequest 方法经过调用 doService 来处理请求,在处理结束后发布了 ServletRequestHandledEvent 事件,能够自定义 ApplicationListener 来监听此事件。缓存
public class DispatcherServlet extends FrameworkServlet { @Override protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception { .....// 省略日志 // 若是 attributes含有 “javax.servlet.include.request_uri”,保留属性的快照 // 用于支持 <jsp:incluede> Map<String, Object> attributesSnapshot = null; if (WebUtils.isIncludeRequest(request)) { attributesSnapshot = new HashMap<>(); // 获取属性枚举 Enumeration<?> attrNames = request.getAttributeNames(); while (attrNames.hasMoreElements()) { String attrName = (String) attrNames.nextElement(); if (this.cleanupAfterInclude || attrName.startsWith(DEFAULT_STRATEGIES_PREFIX)) { // 将属性压入map中 attributesSnapshot.put(attrName, request.getAttribute(attrName)); } } } // 设置上下文、解析器等属性 request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext()); request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver); request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver); request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource()); // 取出上一个请求的 FlashMap并给赋值给当前请求 FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response); if (inputFlashMap != null) { request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap)); } request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap()); request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager); try { // 关注此方法 doDispatch(request, response); } finally { if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) { // 还原属性快照 if (attributesSnapshot != null) { restoreAttributesAfterInclude(request, attributesSnapshot); } } } } }
DispatcherServlet 来进行主要的处理实现。doService 进行一些属性的设置以后,调用 doDispatch 方法进行处理session
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 { /** * 调用咱们配置的 MultipartResolver判断是否须要处理,若是没配置不会处理 * 以 CommonsMultipartResolver为例 * 检测 contentType是否为 multipart/form-data且必须是 POST请求 */ processedRequest = checkMultipart(request); // 若是知足上述条件,会包装成 DefaultMultipartHttpServletRequest // 因此 multipartRequestParsed 为 true multipartRequestParsed = (processedRequest != request); // 根据 request找到对应的 Handler mappedHandler = getHandler(processedRequest); if (mappedHandler == null) { // 没找到 Handler,经过response响应 404错误信息 noHandlerFound(processedRequest, response); return; } // 根据 Handler找到对应的适配器 HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); // 对 last-modified 头支持:只有 Get 和 Head请求支持 String method = request.getMethod(); boolean isGet = "GET".equals(method); if (isGet || "HEAD".equals(method)) { long lastModified = ha.getLastModified(request, mappedHandler.getHandler()); ....// 省略日志 // 对于缓存逻辑的判断,见 ServletWebRequest.checkNotModified if (new ServletWebRequest(request, response). checkNotModified(lastModified) && isGet) { // 知足条件直接返回 return; } } // 调用拦截器的 preHandle,返回true才能经过 if (!mappedHandler.applyPreHandle(processedRequest, response)) { return; } // 调用 HandlerAdapter.handle返回处理后的 ModelAndView mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); if (asyncManager.isConcurrentHandlingStarted()) { return; } // 若是没有 ModelAndView返回,则根据请求默认给出一个视图名称 applyDefaultViewName(processedRequest, mv); // 调用拦截器的 postHandle mappedHandler.applyPostHandle(processedRequest, response, mv); } catch (Exception ex) { dispatchException = ex; } catch (Throwable err) { dispatchException = new NestedServletException("Handler dispatch failed", err); } // 视图处理(包含异常视图),最后会调用拦截器的 triggerAfterCompletion 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()) { if (mappedHandler != null) { // 调用 AsyncHandlerInterceptor.afterConcurrentHandlingStarted // 用于在异步请求处理开始以后回调 mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response); } } else { // 若是是文件上传请求,须要清理资源 if (multipartRequestParsed) { cleanupMultipart(processedRequest); } } } }
经过层层的调用,终于来到了 doDispatch ,这个方法大体可以看到请求的处理步骤概览:app
接下来咱们来看几个主要步骤的解析。框架
@Nullable protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { if (this.handlerMappings != null) { // 遍历全部注册的 HandlerMapping for (HandlerMapping hm : this.handlerMappings) { ....// 省略日志 // 找到匹配的HandlerExecutionChain(不为null) HandlerExecutionChain handler = hm.getHandler(request); if (handler != null) { return handler; } } } return null; }
调用 HandlerMapping.getHandler 获取请求对应的 Handler。来看实现:异步
public abstract class AbstractHandlerMapping extends WebApplicationObjectSupport implements HandlerMapping, Ordered { @Override @Nullable public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { // 根据 request获取对应的 Handler(子类实现) Object handler = getHandlerInternal(request); // 若是没有找到对应 Handler,使用默认Handler if (handler == null) { handler = getDefaultHandler(); } // 若是默认的 Handler没有,则返回 null if (handler == null) { return null; } // Handler为 String类型,说明是beanName,调用 getBean获取 if (handler instanceof String) { String handlerName = (String) handler; handler = obtainApplicationContext().getBean(handlerName); } // 执行链构造:Handler和拦截器 HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request); // 判断跨域请求:是否带有“Origin”请求头 if (CorsUtils.isCorsRequest(request)) { // 全局跨域配置 CorsConfiguration globalConfig = this.globalCorsConfigSource.getCorsConfiguration(request); // 单个 Handler配置(注解 @CrossOrigin其实就是对单个 Handler的配置) CorsConfiguration handlerConfig = getCorsConfiguration(handler, request); // 配置合并 CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig); // 添加 CorsInterceptor拦截器(使用合并后的配置) executionChain = getCorsHandlerExecutionChain(request, executionChain, config); } return executionChain; } // 执行链构造 protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) { HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ? (HandlerExecutionChain) handler : new HandlerExecutionChain(handler)); String lookupPath = this.urlPathHelper.getLookupPathForRequest(request); // 遍历 List<HandlerInterceptor> for (HandlerInterceptor interceptor : this.adaptedInterceptors) { if (interceptor instanceof MappedInterceptor) { MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor; if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) { // 将匹配的 MappedInterceptor加入处理链 chain.addInterceptor(mappedInterceptor.getInterceptor()); } } else { // 其余的直接加入 chain.addInterceptor(interceptor); } } return chain; } // 跨域拦截器加入 protected HandlerExecutionChain getCorsHandlerExecutionChain(HttpServletRequest request, HandlerExecutionChain chain, CorsConfiguration config) { // 条件:带有“Origin”、“Access-Control-Request-Method”请求头的 options请求 if (CorsUtils.isPreFlightRequest(request)) { HandlerInterceptor[] interceptors = chain.getInterceptors(); // 使用 PreFlightHandler替代本来的 Handler处理请求 chain = new HandlerExecutionChain(new PreFlightHandler(config), interceptors); } else { // 添加 CorsInterceptor拦截器(拦截器末尾) chain.addInterceptor(new CorsInterceptor(config)); } return chain; } }
抽象父类 AbstractHandlerMapping 实现了 执行链的构造 以及 “跨域”相关处理(拦截器),查找 Handler 的逻辑交由子类实现(getHandlerInternal)。回想一下 HandlerMapping 注册 Handler 的逻辑分为了两个分支 AbstractUrlHandlerMapping 和 AbstractHandlerMethodMapping (见 HandlerMapping 初始化),所以查找逻辑也随注册逻辑不一样而不一样。jsp
public abstract class AbstractUrlHandlerMapping extends AbstractHandlerMapping implements MatchableHandlerMapping { @Override protected Object getHandlerInternal(HttpServletRequest request) throws Exception { // 这一步咱们会取到截取后的请求相对地址 String lookupPath = getUrlPathHelper().getLookupPathForRequest(request); // 根据相对地址找到对应的 Handler Object handler = lookupHandler(lookupPath, request); if (handler == null) { // 没有的话,依次查询根 Handler、默认 Handler Object rawHandler = null; if ("/".equals(lookupPath)) { rawHandler = getRootHandler(); } if (rawHandler == null) { rawHandler = getDefaultHandler(); } if (rawHandler != null) { // 若是 Handler是 beanName,调用 getBean获取 if (rawHandler instanceof String) { String handlerName = (String) rawHandler; rawHandler = getApplicationContext().getBean(handlerName); } // 校验:由 DefaultAnnotationHandlerMapping实现 // 看请求是否知足 @RequestMapping指定的 method、param、header validateHandler(rawHandler, request); // 使用 Handler建立执行链,链头添加 PathExposingHandlerInterceptor拦截器 handler = buildPathExposingHandler(rawHandler, lookupPath, lookupPath, null); } } ....// 省略日志 return handler; } protected Object lookupHandler(String urlPath, HttpServletRequest request) throws Exception { // 从映射关系中找出请求对应的 Handler(直接路径) // 映射关系的初始化见 HandlerMapping初始化 Object handler = this.handlerMap.get(urlPath); if (handler != null) { // beanName以及 Handler校验,上面讲过了 if (handler instanceof String) { String handlerName = (String) handler; handler = getApplicationContext().getBean(handlerName); } validateHandler(handler, request); // 构造执行链 return buildPathExposingHandler(handler, urlPath, urlPath, null); } // 直接路径中未找到,使用通配符匹配 List<String> matchingPatterns = new ArrayList<String>(); for (String registeredPattern : this.handlerMap.keySet()) { if (getPathMatcher().match(registeredPattern, urlPath)) { matchingPatterns.add(registeredPattern); } else if (useTrailingSlashMatch()) { if (!registeredPattern.endsWith("/") && getPathMatcher().match(registeredPattern + "/", urlPath)) { matchingPatterns.add(registeredPattern + "/"); } } } String bestMatch = null; // 使用模式匹配后,查找最匹配的 Handler Comparator<String> patternComparator = getPathMatcher().getPatternComparator(urlPath); if (!matchingPatterns.isEmpty()) { Collections.sort(matchingPatterns, patternComparator); ....// 省略日志 bestMatch = matchingPatterns.get(0); } if (bestMatch != null) { handler = this.handlerMap.get(bestMatch); if (handler == null) { if (bestMatch.endsWith("/")) { handler = this.handlerMap.get(bestMatch.substring(0, bestMatch.length() - 1)); } if (handler == null) { throw new IllegalStateException( "Could not find handler for best pattern match [" + bestMatch + "]"); } } // beanName以及 Handler校验,上面讲过了 if (handler instanceof String) { String handlerName = (String) handler; handler = getApplicationContext().getBean(handlerName); } validateHandler(handler, request); String pathWithinMapping = getPathMatcher().extractPathWithinPattern(bestMatch, urlPath); // 可能存在多个“最佳模式”,让咱们确保全部这些模式都有正确的URI模板变量 Map<String, String> uriTemplateVariables = new LinkedHashMap<String, String>(); for (String matchingPattern : matchingPatterns) { if (patternComparator.compare(bestMatch, matchingPattern) == 0) { Map<String, String> vars = getPathMatcher().extractUriTemplateVariables(matchingPattern, urlPath); Map<String, String> decodedVars = getUrlPathHelper().decodePathVariables(request, vars); uriTemplateVariables.putAll(decodedVars); } } ....// 省略日志 // 构造执行链 return buildPathExposingHandler(handler, bestMatch, pathWithinMapping, uriTemplateVariables); } // 没有匹配的 Handler返回 null return null; } }
首先调用 UrlPathHelper.getLookupPathForRequest 获取请求的相对路径。以 Tomcat 举例,配置的 <Context path="xxx"> 项目根路径,那么对应的 web 应用全部的请求,都要添加 “xxx” 前缀,但咱们的应用对此是无感知的,因此框架层面要把这些截取后,再去查找 Handler。来看下截取逻辑:
public class UrlPathHelper { public String getLookupPathForRequest(HttpServletRequest request) { // 默认为 false if (this.alwaysUseFullPath) { return getPathWithinApplication(request); } String rest = getPathWithinServletMapping(request); if (!"".equals(rest)) { return rest; } else { return getPathWithinApplication(request); } } public String getPathWithinServletMapping(HttpServletRequest request) { // 获取截取后的相对地址 String pathWithinApp = getPathWithinApplication(request); // 获取的 <servlet>指定的 <url-pattern>(移除通配符后) String servletPath = getServletPath(request); // 把 pathWithinApp中的“//”替换成“/” String sanitizedPathWithinApp = getSanitizedPath(pathWithinApp); String path; // 这一步主要就是对请求地址中多余的“/”进行移除匹配 if (servletPath.contains(sanitizedPathWithinApp)) { // 一样的,把请求的相对地址中,servletPath截取掉 path = getRemainingPath(sanitizedPathWithinApp, servletPath, false); } else { // 一样的,把请求的相对地址中,servletPath截取掉 path = getRemainingPath(pathWithinApp, servletPath, false); } if (path != null) { return path; } else { // 若是请求不在 servlet指定的 <url-pattern>下 String pathInfo = request.getPathInfo(); if (pathInfo != null) { return pathInfo; } if (!this.urlDecode) { path = getRemainingPath(decodeInternal(request, pathWithinApp), servletPath, false); if (path != null) { return pathWithinApp; } } return servletPath; } } public String getPathWithinApplication(HttpServletRequest request) { // 获取的项目根路径 String contextPath = getContextPath(request); // 获取请求的相对地址 String requestUri = getRequestUri(request); // 把请求的相对地址中的项目根路径截去 String path = getRemainingPath(requestUri, contextPath, true); if (path != null) { return (StringUtils.hasText(path) ? path : "/"); } else { return requestUri; } } }
(getPathWithinServletMapping)首先会在配置的 DispatcherServlet 范围内查找,对于同一个请求 “http://localhost/a/b” 来讲:
(getPathWithinApplication)只有在上一步返回空字符串时才会在 Application 范围内查找,对于用一个请求“http://localhost/context/a” 来讲:
public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMapping implements InitializingBean { @Override protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception { // 一样使用 UrlPathHelper.getLookupPathForRequest String lookupPath = getUrlPathHelper().getLookupPathForRequest(request); if (logger.isDebugEnabled()) { logger.debug("Looking up handler method for path " + lookupPath); } this.mappingRegistry.acquireReadLock(); try { // 根据请求 url找到对应的 HandlerMethod HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request); ....// 省略日志 // createWithResolvedBean目的是确保 HandlerMethod中持有的是被调用的实例 bean // 而不是 beanName,若是是会调用了 getBean获取实例后建立新的 HandleMethod // 由于这个实例 bean会用于反射调用方法 return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null); } finally { this.mappingRegistry.releaseReadLock(); } } protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception { List<Match> matches = new ArrayList<Match>(); // 使用 MappingRegistry.getMappingsByUrl,经过相对路径查找对应的 List<RequestMappingInfo> // 见 AbstractHandlerMethodMapping的注册逻辑 List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath); if (directPathMatches != null) { // 不为 null,说明 @RequestMapping指定的是非通配符路径 // 找到匹配条件的填充 matches addMatchingMappings(directPathMatches, matches, request); } if (matches.isEmpty()) { // 若是经过直接路径找不到,就在全部注册的映射路径中查找 // 找到匹配条件的填充 matches addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request); } if (!matches.isEmpty()) { // 由于可能会有多个匹配方法,须要根据定义的优先级排序 Comparator<Match> comparator = new MatchComparator(getMappingComparator(request)); Collections.sort(matches, comparator); if (logger.isTraceEnabled()) { logger.trace("Found " + matches.size() + " matching mapping(s) for [" + lookupPath + "] : " + matches); } // 取出最匹配的 Match bestMatch = matches.get(0); if (matches.size() > 1) { // 条件:带有“Origin”、“Access-Control-Request-Method”请求头的 options请求 if (CorsUtils.isPreFlightRequest(request)) { // 返回 EmptyHandler封装的 HandlerMethod // 调用会抛出异常 UnsupportedOperationException 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 + "}"); } } // 调用 setAttribute设置一些属性 handleMatch(bestMatch.mapping, lookupPath, request); // 返回匹配的 HandlerMethod return bestMatch.handlerMethod; } else { // 未匹配 return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request); } } }
一样使用的是 UrlPathHelper.getLookupPathForRequest 获取请求的相对路径。以后根据相对路径找到对应的 HandlerMethod 。涉及到了一个请求地址对应了多个匹配结果的筛选:
private void addMatchingMappings(Collection<T> mappings, List<Match> matches, HttpServletRequest request) { for (T mapping : mappings) { // 获取知足条件的 RequestMappingInfo T match = getMatchingMapping(mapping, request); // 只有知足返回的才不为 null,这一步会筛选掉不符合条件的 // 例如:请求路径不匹配、header头不匹配等等 if (match != null) { // 经过 MappingRegistry维护的 mappingLookup找到对应的 HandlerMethod // 使用 RequestMappingInfo和 HandlerMethod建立 Match // 用于 MatchComparator的排序 matches.add(new Match(match, this.mappingRegistry.getMappings().get(mapping))); } } }
public abstract class RequestMappingInfoHandlerMapping extends AbstractHandlerMethodMapping<RequestMappingInfo> { @Override protected RequestMappingInfo getMatchingMapping(RequestMappingInfo info, HttpServletRequest request) { // 调用 RequestMappingInfo.getMatchingCondition return info.getMatchingCondition(request); } }
public final class RequestMappingInfo implements RequestCondition<RequestMappingInfo> { @Override public RequestMappingInfo getMatchingCondition(HttpServletRequest request) { RequestMethodsRequestCondition methods = this.methodsCondition.getMatchingCondition(request); ParamsRequestCondition params = this.paramsCondition.getMatchingCondition(request); HeadersRequestCondition headers = this.headersCondition.getMatchingCondition(request); ConsumesRequestCondition consumes = this.consumesCondition.getMatchingCondition(request); ProducesRequestCondition produces = this.producesCondition.getMatchingCondition(request); // 这一步基本不会,由于 @RequestMapping都有默认值 if (methods == null || params == null || headers == null || consumes == null || produces == null) { return null; } // 对于 @RequestMapping指定的 path/value匹配(直接地址匹配、通配符匹配) PatternsRequestCondition patterns = this.patternsCondition.getMatchingCondition(request); if (patterns == null) { return null; } // 对于 @RequestMapping指定的 method、param、header、consumes、produces的匹配 RequestConditionHolder custom = this.customConditionHolder.getMatchingCondition(request); if (custom == null) { return null; } return new RequestMappingInfo(this.name, patterns, methods, params, headers, consumes, produces, custom.getCondition()); } }
以上的源码,就是用知足请求条件的(指定的 method、header等) RequestMappingInfo 以及对应的 HandlerMethod 封装成 Match, 并填充到 matches 的逻辑。
这一步可能会筛选出多个匹配项,接下来就须要靠 MatchComparator 排序后挑选出最匹配项,逻辑见 RequestMappingInfo.compareTo,这里不展开分析。
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException { if (this.handlerAdapters != null) { // 遍历全部注册的 HandlerAdapter for (HandlerAdapter ha : this.handlerAdapters) { if (logger.isTraceEnabled()) { logger.trace("Testing handler adapter [" + ha + "]"); } // 调用 HandlerAdapter.supports看是否支持适配 if (ha.supports(handler)) { return ha; } } } throw new ServletException("No adapter for handler [" + handler + "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler"); }
这里调用的 supports 获取到支持适配的 HandlerAdapter,以后调用其 handle 方法执行处理逻辑,具体源码上篇已分析,见 “HandlerAdapter”。
执行完以后,就获取到了 ModelAndView 返回,接着就是对视图的处理(processDispatchResult),放在下节分析。
本篇分析的就是一个请求从接收处处理的全过程,目前进度已经获取到了 ModelAndView,至于请求地址如何找到对应的 Handler、Handler 如何调用并返回 ModelAndView ,前几篇已做讲解。下篇将分析 “视图处理” 源码。