博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
spring mvc如何计算BEST_MATCHING_PATTERN_ATTRIBUTE
阅读量:6983 次
发布时间:2019-06-27

本文共 14639 字,大约阅读时间需要 48 分钟。

本文主要研究一下spring mvc如何计算best-matching-pattern

DispatcherServlet

spring-webmvc-4.3.10.RELEASE-sources.jar!/org/springframework/web/servlet/DispatcherServlet.java

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 {                processedRequest = checkMultipart(request);                multipartRequestParsed = (processedRequest != request);                // Determine handler for the current request.                mappedHandler = getHandler(processedRequest);                if (mappedHandler == null || mappedHandler.getHandler() == null) {                    noHandlerFound(processedRequest, response);                    return;                }                // Determine handler adapter for the current request.                HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());                // Process last-modified header, if supported by the handler.                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;                    }                }                if (!mappedHandler.applyPreHandle(processedRequest, response)) {                    return;                }                // Actually invoke the handler.                mv = ha.handle(processedRequest, response, mappedHandler.getHandler());                if (asyncManager.isConcurrentHandlingStarted()) {                    return;                }                applyDefaultViewName(processedRequest, mv);                mappedHandler.applyPostHandle(processedRequest, response, mv);            }            catch (Exception ex) {                dispatchException = ex;            }            catch (Throwable err) {                // As of 4.3, we're processing Errors thrown from handler methods as well,                // making them available for @ExceptionHandler methods and other scenarios.                dispatchException = new NestedServletException("Handler dispatch failed", err);            }            processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);        }        catch (Exception ex) {            triggerAfterCompletion(processedRequest, response, mappedHandler, ex);        }        catch (Throwable err) {            triggerAfterCompletion(processedRequest, response, mappedHandler,                    new NestedServletException("Handler processing failed", err));        }        finally {            if (asyncManager.isConcurrentHandlingStarted()) {                // Instead of postHandle and afterCompletion                if (mappedHandler != null) {                    mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);                }            }            else {                // Clean up any resources used by a multipart request.                if (multipartRequestParsed) {                    cleanupMultipart(processedRequest);                }            }        }    }

主要看mappedHandler = getHandler(processedRequest);这段

/**     * Return the HandlerExecutionChain for this request.     * 

Tries all handler mappings in order. * @param request current HTTP request * @return the HandlerExecutionChain, or {@code null} if no handler could be found */ protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { for (HandlerMapping hm : this.handlerMappings) { if (logger.isTraceEnabled()) { logger.trace( "Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'"); } HandlerExecutionChain handler = hm.getHandler(request); if (handler != null) { return handler; } } return null; }

这里的handlerMappings主要有:

  • SimpleUrlHandlerMapping
  • EndpointHandlerMapping
  • ReuqestMappingHandlerMapping
  • BeanNameUrlHandlerMapping
  • WebMvcConfigurationSupport$EmptyHandlerMapping

主要有抽象类AbstractHandlerMapping来执行

AbstractHandlerMapping#getHandler

spring-webmvc-4.3.10.RELEASE-sources.jar!/org/springframework/web/servlet/handler/AbstractHandlerMapping.java

/**     * Look up a handler for the given request, falling back to the default     * handler if no specific one is found.     * @param request current HTTP request     * @return the corresponding handler instance, or the default handler     * @see #getHandlerInternal     */    @Override    public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {        Object handler = getHandlerInternal(request);        if (handler == null) {            handler = getDefaultHandler();        }        if (handler == null) {            return null;        }        // Bean name or resolved handler?        if (handler instanceof String) {            String handlerName = (String) handler;            handler = getApplicationContext().getBean(handlerName);        }        HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);        if (CorsUtils.isCorsRequest(request)) {            CorsConfiguration globalConfig = this.corsConfigSource.getCorsConfiguration(request);            CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);            CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);            executionChain = getCorsHandlerExecutionChain(request, executionChain, config);        }        return executionChain;    }

这里主要看Object handler = getHandlerInternal(request);这段

AbstractUrlHandlerMapping#getHandlerInternal

spring-webmvc-4.3.12.RELEASE-sources.jar!/org/springframework/web/servlet/handler/AbstractUrlHandlerMapping.java

/**     * Look up a handler for the URL path of the given request.     * @param request current HTTP request     * @return the handler instance, or {@code null} if none found     */    @Override    protected Object getHandlerInternal(HttpServletRequest request) throws Exception {        String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);        Object handler = lookupHandler(lookupPath, request);        if (handler == null) {            // We need to care for the default handler directly, since we need to            // expose the PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE for it as well.            Object rawHandler = null;            if ("/".equals(lookupPath)) {                rawHandler = getRootHandler();            }            if (rawHandler == null) {                rawHandler = getDefaultHandler();            }            if (rawHandler != null) {                // Bean name or resolved handler?                if (rawHandler instanceof String) {                    String handlerName = (String) rawHandler;                    rawHandler = getApplicationContext().getBean(handlerName);                }                validateHandler(rawHandler, request);                handler = buildPathExposingHandler(rawHandler, lookupPath, lookupPath, null);            }        }        if (handler != null && logger.isDebugEnabled()) {            logger.debug("Mapping [" + lookupPath + "] to " + handler);        }        else if (handler == null && logger.isTraceEnabled()) {            logger.trace("No handler mapping found for [" + lookupPath + "]");        }        return handler;    }

这里主要看lookupHandler

AbstractUrlHandlerMapping#lookupHandler

spring-webmvc-4.3.12.RELEASE-sources.jar!/org/springframework/web/servlet/handler/AbstractUrlHandlerMapping.java

protected Object lookupHandler(String urlPath, HttpServletRequest request) throws Exception {        // Direct match?        Object handler = this.handlerMap.get(urlPath);        if (handler != null) {            // Bean name or resolved handler?            if (handler instanceof String) {                String handlerName = (String) handler;                handler = getApplicationContext().getBean(handlerName);            }            validateHandler(handler, request);            return buildPathExposingHandler(handler, urlPath, urlPath, null);        }        // Pattern match?        List
matchingPatterns = new ArrayList
(); 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; Comparator
patternComparator = getPathMatcher().getPatternComparator(urlPath); if (!matchingPatterns.isEmpty()) { Collections.sort(matchingPatterns, patternComparator); if (logger.isDebugEnabled()) { logger.debug("Matching patterns for request [" + urlPath + "] are " + matchingPatterns); } 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 + "]"); } } // Bean name or resolved handler? if (handler instanceof String) { String handlerName = (String) handler; handler = getApplicationContext().getBean(handlerName); } validateHandler(handler, request); String pathWithinMapping = getPathMatcher().extractPathWithinPattern(bestMatch, urlPath); // There might be multiple 'best patterns', let's make sure we have the correct URI template variables // for all of them Map
uriTemplateVariables = new LinkedHashMap
(); for (String matchingPattern : matchingPatterns) { if (patternComparator.compare(bestMatch, matchingPattern) == 0) { Map
vars = getPathMatcher().extractUriTemplateVariables(matchingPattern, urlPath); Map
decodedVars = getUrlPathHelper().decodePathVariables(request, vars); uriTemplateVariables.putAll(decodedVars); } } if (logger.isDebugEnabled()) { logger.debug("URI Template variables for request [" + urlPath + "] are " + uriTemplateVariables); } return buildPathExposingHandler(handler, bestMatch, pathWithinMapping, uriTemplateVariables); } // No handler found... return null; }

这里就是bestMatch计算的核心

设置

计算完bestMatch之后,就是设置,主要是调用AbstractUrlHandlerMapping#buildPathExposingHandler

/**     * Build a handler object for the given raw handler, exposing the actual     * handler, the {@link #PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE}, as well as     * the {@link #URI_TEMPLATE_VARIABLES_ATTRIBUTE} before executing the handler.     * 

The default implementation builds a {@link HandlerExecutionChain} * with a special interceptor that exposes the path attribute and uri template variables * @param rawHandler the raw handler to expose * @param pathWithinMapping the path to expose before executing the handler * @param uriTemplateVariables the URI template variables, can be {@code null} if no variables found * @return the final handler object */ protected Object buildPathExposingHandler(Object rawHandler, String bestMatchingPattern, String pathWithinMapping, Map

uriTemplateVariables) { HandlerExecutionChain chain = new HandlerExecutionChain(rawHandler); chain.addInterceptor(new PathExposingHandlerInterceptor(bestMatchingPattern, pathWithinMapping)); if (!CollectionUtils.isEmpty(uriTemplateVariables)) { chain.addInterceptor(new UriTemplateVariablesHandlerInterceptor(uriTemplateVariables)); } return chain; }

而这个方法,new了一个PathExposingHandlerInterceptor

/**     * Special interceptor for exposing the     * {@link AbstractUrlHandlerMapping#PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE} attribute.     * @see AbstractUrlHandlerMapping#exposePathWithinMapping     */    private class PathExposingHandlerInterceptor extends HandlerInterceptorAdapter {        private final String bestMatchingPattern;        private final String pathWithinMapping;        public PathExposingHandlerInterceptor(String bestMatchingPattern, String pathWithinMapping) {            this.bestMatchingPattern = bestMatchingPattern;            this.pathWithinMapping = pathWithinMapping;        }        @Override        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {            exposePathWithinMapping(this.bestMatchingPattern, this.pathWithinMapping, request);            request.setAttribute(INTROSPECT_TYPE_LEVEL_MAPPING, supportsTypeLevelMappings());            return true;        }    }    /**     * Expose the path within the current mapping as request attribute.     * @param pathWithinMapping the path within the current mapping     * @param request the request to expose the path to     * @see #PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE     */    protected void exposePathWithinMapping(String bestMatchingPattern, String pathWithinMapping, HttpServletRequest request) {        request.setAttribute(BEST_MATCHING_PATTERN_ATTRIBUTE, bestMatchingPattern);        request.setAttribute(PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE, pathWithinMapping);    }

可以看到,这里通过exposePathWithinMapping方法设置了BEST_MATCHING_PATTERN_ATTRIBUTE

转载地址:http://rltpl.baihongyu.com/

你可能感兴趣的文章
【MOS】RAC 环境中最常见的 5 个数据库和/或实例性能问题 (文档 ID 1602076.1)
查看>>
新年图书整理和相关的产品
查看>>
Struts2的核心文件
查看>>
Spring Boot集成Jasypt安全框架
查看>>
GIS基础软件及操作(十)
查看>>
HDOJ 2041 超级楼梯
查看>>
1108File Space Bitmap Block损坏能修复吗2
查看>>
遭遇DBD::mysql::dr::imp_data_size unexpectedly
查看>>
人人都会设计模式:03-策略模式--Strategy
查看>>
被忽视但很实用的那部分SQL
查看>>
解读阿里云oss-android/ios-sdk 断点续传(多线程)
查看>>
ML之监督学习算法之分类算法一 ——— 决策树算法
查看>>
骡夫电商地址
查看>>
亚信安全火力全开猎捕“坏兔子”,全歼详解
查看>>
智能家居——IoT零基础入门篇
查看>>
《Linux From Scratch》第一部分:介绍 第一章:介绍-1.3. 更新日志
查看>>
阿里将在雄安新区设3家子公司:涉AI、蚂蚁金服和菜鸟;北航设立全国首个人工智能专业,与百度合作办学...
查看>>
Powershell指令集_2
查看>>
归并排序算法
查看>>
北京第一个公共云计算平台即将诞生
查看>>