当前位置: 首页 > news >正文

ico 众筹网站开发简单网页模板

ico 众筹网站开发,简单网页模板,网站建设氵金手指下拉,深圳市做网站有哪些公司2019独角兽企业重金招聘Python工程师标准 前言 这一篇#xff0c;将着手介绍一次请求的处理。用到了 HandlerMapping、HandlerAdapter 知识#xff0c;如果遇到不是太了解#xff0c;可以回顾下。 源码分析 其实 DispatcherServlet 也只是 Servlet 的一个实现… 2019独角兽企业重金招聘Python工程师标准 前言     这一篇将着手介绍一次请求的处理。用到了 HandlerMapping、HandlerAdapter 知识如果遇到不是太了解可以回顾下。   源码分析     其实 DispatcherServlet 也只是 Servlet 的一个实现只不过它集成了 SpringMVC 的几个功能组件例如视图解析器对请求及响应进行加工处理所以探索一个 Servlet 实现先从它的 service 方法实现开始来看下 javax.servlet.http.HttpServlet 的实现。 public abstract class HttpServlet extends GenericServlet {Overridepublic 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 如何在此基础上改造。 // HttpServletBean是 HttpServlet子类 public abstract class FrameworkServlet extends HttpServletBean implements ApplicationContextAware {// 覆盖 service方法Overrideprotected 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);}}Overrideprotected final void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {processRequest(request, response);}Overrideprotected 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请求头构造 LocaleContextLocaleContext localeContext buildLocaleContext(request);// 获取当前线程请求的 RequestAttributesRequestAttributes 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) {// 默认为 trueif (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 来监听此事件。   doService public class DispatcherServlet extends FrameworkServlet {Overrideprotected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {.....// 省略日志// 如果 attributes含有 “javax.servlet.include.request_uri”保留属性的快照// 用于支持 jsp:incluedeMapString, 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 方法进行处理   doDispatch 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 为 truemultipartRequestParsed (processedRequest ! request);// 根据 request找到对应的 HandlermappedHandler 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.checkNotModifiedif (new ServletWebRequest(request, response).checkNotModified(lastModified) isGet) {// 满足条件直接返回return;}}// 调用拦截器的 preHandle返回true才能通过if (!mappedHandler.applyPreHandle(processedRequest, response)) {return;}// 调用 HandlerAdapter.handle返回处理后的 ModelAndViewmv ha.handle(processedRequest, response, mappedHandler.getHandler());if (asyncManager.isConcurrentHandlingStarted()) {return;}// 如果没有 ModelAndView返回则根据请求默认给出一个视图名称applyDefaultViewName(processedRequest, mv);// 调用拦截器的 postHandlemappedHandler.applyPostHandle(processedRequest, response, mv);} catch (Exception ex) {dispatchException ex;} catch (Throwable err) {dispatchException new NestedServletException(Handler dispatch failed, err);}// 视图处理包含异常视图最后会调用拦截器的 triggerAfterCompletionprocessDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);} catch (Exception ex) {// 调用拦截器的 triggerAfterCompletiontriggerAfterCompletion(processedRequest, response, mappedHandler, ex);} catch (Throwable err) {// 调用拦截器的 triggerAfterCompletiontriggerAfterCompletion(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 这个方法大致能够看到请求的处理步骤概览 首先判断是否为文件上传的请求和普通的请求不一样这种请求需要在请求结束后清理文件解析过程中创建的 MultipartFile 可能会在磁盘上保留有临时数据获取 Handler 从 HandlerMapping初始化建立的映射关系中找出拦截器 HandlerInterceptor.preHandle 调用HandlerAdapter 适配从 HandlerAdapter 初始化注册的所有适配器中找到支持对应 Handler 的适配器调用 handle 方法处理见 HandlerAdapter拦截器 HandlerInterceptor.postHandle 调用调用 processDispatchResult 进行视图处理拦截器 HandlerInterceptor.afterCompletion 调用异常同样会触发并且会作为参数传入    接下来我们来看几个主要步骤的解析。   getHandler Nullableprotected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {if (this.handlerMappings ! null) {// 遍历所有注册的 HandlerMappingfor (HandlerMapping hm : this.handlerMappings) {....// 省略日志// 找到匹配的HandlerExecutionChain不为nullHandlerExecutionChain handler hm.getHandler(request);if (handler ! null) {return handler;}}}return null;}     调用 HandlerMapping.getHandler 获取请求对应的 Handler。来看实现 public abstract class AbstractHandlerMapping extends WebApplicationObjectSupport implements HandlerMapping, Ordered {OverrideNullablepublic final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {// 根据 request获取对应的 Handler子类实现Object handler getHandlerInternal(request);// 如果没有找到对应 Handler使用默认Handlerif (handler null) {handler getDefaultHandler();}// 如果默认的 Handler没有则返回 nullif (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);// 遍历 ListHandlerInterceptorfor (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 初始化因此查找逻辑也随注册逻辑不同而不同。   AbstractUrlHandlerMapping 分支 public abstract class AbstractUrlHandlerMapping extends AbstractHandlerMapping implements MatchableHandlerMapping {Overrideprotected Object getHandlerInternal(HttpServletRequest request) throws Exception {// 这一步我们会取到截取后的请求相对地址String lookupPath getUrlPathHelper().getLookupPathForRequest(request);// 根据相对地址找到对应的 HandlerObject handler lookupHandler(lookupPath, request);if (handler null) {// 没有的话依次查询根 Handler、默认 HandlerObject 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、headervalidateHandler(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);}// 直接路径中未找到使用通配符匹配ListString matchingPatterns new ArrayListString();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;// 使用模式匹配后查找最匹配的 HandlerComparatorString 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模板变量MapString, String uriTemplateVariables new LinkedHashMapString, String();for (String matchingPattern : matchingPatterns) {if (patternComparator.compare(bestMatch, matchingPattern) 0) {MapString, String vars getPathMatcher().extractUriTemplateVariables(matchingPattern, urlPath);MapString, String decodedVars getUrlPathHelper().decodePathVariables(request, vars);uriTemplateVariables.putAll(decodedVars);}}....// 省略日志// 构造执行链return buildPathExposingHandler(handler, bestMatch, pathWithinMapping, uriTemplateVariables);}// 没有匹配的 Handler返回 nullreturn null;} }     首先调用 UrlPathHelper.getLookupPathForRequest 获取请求的相对路径。以 Tomcat 举例配置的 Context pathxxx 项目根路径那么对应的 web 应用所有的请求都要添加 “xxx” 前缀但我们的应用对此是无感知的所以框架层面要把这些截取后再去查找 Handler。来看下截取逻辑 public class UrlPathHelper {public String getLookupPathForRequest(HttpServletRequest request) {// 默认为 falseif (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” 来说 url-pattern/*/url-pattern 返回的就是 “/a/b”url-pattern/a/*/url-pattern那么返回的就是 “/b”。如果请求为 “http://localhost/a” 那么返回的就是空字符串了。    getPathWithinApplication只有在上一步返回空字符串时才会在 Application 范围内查找对于用一个请求“http://localhost/context/a” 来说 Context path/context返回的就是 “/a”Context path/返回的就是 “/context/a”。如果请求为 “http://localhost” 那么返回的就是 “/”了。  AbstractHandlerMethodMapping 分支 public abstract class AbstractHandlerMethodMappingT extends AbstractHandlerMapping implements InitializingBean {Overrideprotected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {// 同样使用 UrlPathHelper.getLookupPathForRequestString lookupPath getUrlPathHelper().getLookupPathForRequest(request);if (logger.isDebugEnabled()) {logger.debug(Looking up handler method for path lookupPath);}this.mappingRegistry.acquireReadLock();try {// 根据请求 url找到对应的 HandlerMethodHandlerMethod 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 {ListMatch matches new ArrayListMatch();// 使用 MappingRegistry.getMappingsByUrl通过相对路径查找对应的 ListRequestMappingInfo// 见 AbstractHandlerMethodMapping的注册逻辑ListT directPathMatches this.mappingRegistry.getMappingsByUrl(lookupPath);if (directPathMatches ! null) {// 不为 null说明 RequestMapping指定的是非通配符路径// 找到匹配条件的填充 matchesaddMatchingMappings(directPathMatches, matches, request);}if (matches.isEmpty()) {// 如果通过直接路径找不到就在所有注册的映射路径中查找// 找到匹配条件的填充 matchesaddMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request);}if (!matches.isEmpty()) {// 因为可能会有多个匹配方法需要根据定义的优先级排序ComparatorMatch 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// 调用会抛出异常 UnsupportedOperationExceptionreturn 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);// 返回匹配的 HandlerMethodreturn bestMatch.handlerMethod;} else {// 未匹配return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);}} }     同样使用的是 UrlPathHelper.getLookupPathForRequest 获取请求的相对路径。之后根据相对路径找到对应的 HandlerMethod 。涉及到了一个请求地址对应了多个匹配结果的筛选 private void addMatchingMappings(CollectionT mappings, ListMatch matches, HttpServletRequest request) {for (T mapping : mappings) {// 获取满足条件的 RequestMappingInfoT 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 AbstractHandlerMethodMappingRequestMappingInfo {Overrideprotected RequestMappingInfo getMatchingMapping(RequestMappingInfo info, HttpServletRequest request) {// 调用 RequestMappingInfo.getMatchingConditionreturn info.getMatchingCondition(request);} } public final class RequestMappingInfo implements RequestConditionRequestMappingInfo {Overridepublic 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这里不展开分析。   getHandlerAdapter protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {if (this.handlerAdapters ! null) {// 遍历所有注册的 HandlerAdapterfor (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 前几篇已作讲解。下篇将分析 “视图处理” 源码。 转载于:https://my.oschina.net/marvelcode/blog/1841027
http://www.zqtcl.cn/news/849257/

相关文章:

  • 合肥百度团购网站建设怀化网站开发
  • 网站建设ppt模板彩票网站开发dadi163
  • 网站建设4435建筑设计一般用什么软件
  • 河南网站建设重庆森林台词
  • 网站一直没收录雄安做网站
  • 全国网站直播平台被摧毁响应是网站怎么做
  • 衡阳建设网站做网站和app多少费用
  • 怎么做付费网站蚌埠网站建设专业公司哪家好
  • 学网站建设需要多长时间成都网站建设定制开发服务
  • 建站宝盒后台深圳建网站公司怎么选择
  • 什么是大型门户网站网站建设的经验之谈
  • 网站建站网站设计网站制作书生
  • 租号网站是怎么做的wordpress 快讯功能
  • 口碑好的盐城网站建设wordpress课堂主题
  • 网站品牌打造wordpress插件有木马
  • 网站开发与软件研发有什么区别查网站域名备案查询系统
  • 硬盘做免费嗳暧视频网站黄冈免费网站推广平台汇总
  • node做网站怎么知道蜘蛛来过怎么学网站设计
  • 青海省建设厅网站公示公告简单建站
  • 手机网站用什么后台wordpress 百度蜘蛛
  • 网站文章伪原创怎么做手机网站 程序
  • 网站建设每月工作多少开发小程序的目的
  • 社区网站建设方案pptwordpress用户名在哪看
  • 浙江企业响应式网站建设公司简介如何写
  • 自己做静态网站的步骤店面设计在线
  • 活动汪活动策划网站wordpress 无法保存
  • 门户网站开发案例兰州需要做网站的公司有哪些
  • 东莞企业网站asp网站怎么安装
  • 个人做公司网站网站备案取消接入
  • 崇信网站建设it外包的收益主要有哪些