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

本文共 14667 字,大约阅读时间需要 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://rtcta.baihongyu.com/

你可能感兴趣的文章
关于JAVA匿名内部类,回调,事件模式的一点讨论
查看>>
Windows 术语表(Windows Glossary)
查看>>
TOJ 4689: Sawtooth
查看>>
你会开会吗
查看>>
关于FAST比较全的博文
查看>>
SCVMM 安装
查看>>
iOSBlock和delegate的用法
查看>>
4.Azure创建点到站点的***隧道(下)
查看>>
怎样为用户写“招标书”
查看>>
python运维之轻松模拟开发FTP软件05
查看>>
Nginx配置proxy_pass转发的/路径问题
查看>>
总编下午茶:挑战者心态能否帮助微软重回云计算巅峰?
查看>>
理解并取证:广域网上的PPP协议
查看>>
动软分享社区系统实现个性化导购营销平台
查看>>
shell编程 字符串处理
查看>>
Cisco3560交换机enable密码破解和恢复出厂设置
查看>>
交换安全老师课堂笔记
查看>>
RHEL6基础四十三之RHEL文件共享②Samba简介
查看>>
CuteEditor Html中显示Word格式粘贴的文章[CuteEditor WordToHtml]
查看>>
zabbix 二次开发之调用api接口获取历史数据
查看>>