SpringMVC源码解读

来源:互联网 发布:淘宝条形码是什么意思 编辑:程序博客网 时间:2024/04/29 15:14

AbstractHandlerMethodMapping实现接口getHandlerInternal,定义查找流程

RequestMappingInfoHandlerMapping根据RequestMappingInfo,细化匹配条件,并在匹配不到情况下,顽强的使用RequestCondition一再尝试匹配

虽然 RequestMappingHandlerMapping是受益方,但在这边什么都没做(就是在初始化时,根据@Controller,@RequestMapping注解生成RequestMappingInfo;并根据这两个注解判断是否目标Handler  实现isHandler)

 

AbstractHandlerMethodMapping实现接口getHandlerInternal

  1. 使用UrlPathHelper查找request对应的path

  2. 查找path对应的HandlerMethod

    2.1 从urlMap中直接等值匹配查找匹配条件RequestMappingInfo

    2.2 如果等值查找到匹配条件,将其添加到match条件中

    2.3 如果没有找到匹配条件,使用所有的handlerMethod的RequestMappingInfo进行匹配

    2.4 对匹配到的Match进行排序,取出最高优先级的Match,并核对是否是唯一的最高优先级

    2.5 对匹配到条件,没有匹配到条件的两种情况,分别进行封装

  3. 封装HandlerMethod,确保bean中存的是实例

 

// AbstractHandlerMethodMapping

实现接口getHandlerInternal

复制代码
 1 package org.springframework.web.servlet.handler 2     // AbstractHandlerMethodMapping<T> 3     /** 4      * Look up a handler method for the given request. 5      */ 6     @Override 7     protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception { 8         // 就是request对应的url 9         String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);10         // 查找到处理器,这边的处理器会封装成HandlerMethod11         HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);12         // 确保bean中存的是实例13         return (handlerMethod != null) ? handlerMethod.createWithResolvedBean() : null;14     }
复制代码

 

// AbstractHandlerMethodMapping

复制代码
package org.springframework.web.servlet.handler;public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMapping implements InitializingBean  {    /**     * Look up the best-matching handler method for the current request.     * If multiple matches are found, the best match is selected.     * @param lookupPath mapping lookup path within the current servlet mapping     * @param request the current request     * @return the best-matching handler method, or {@code null} if no match     * @see #handleMatch(Object, String, HttpServletRequest)     * @see #handleNoMatch(Set, String, HttpServletRequest)     */    protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {        List<Match> matches = new ArrayList<Match>();        // 从urlMap中直接等值匹配查找匹配条件RequestMappingInfo        List<T> directPathMatches = this.urlMap.get(lookupPath);        if (directPathMatches != null) {            //             addMatchingMappings(directPathMatches, matches, request);        }        if (matches.isEmpty()) {            // No choice but to go through all mappings            // 没有匹配的情况下,遍历handlerMethods的全部匹配条件进行查找            addMatchingMappings(this.handlerMethods.keySet(), matches, request);        }        if (!matches.isEmpty()) {            Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));            Collections.sort(matches, comparator);            Match bestMatch = matches.get(0);            if (matches.size() > 1) {                Match secondBestMatch = matches.get(1);                if (comparator.compare(bestMatch, secondBestMatch) == 0) {                    Method m1 = bestMatch.handlerMethod.getMethod();                    Method m2 = secondBestMatch.handlerMethod.getMethod();                    // 不能有相同的最优Match                    throw new IllegalStateException(                            "Ambiguous handler methods mapped for HTTP path '" + request.getRequestURL() + "': {" +                            m1 + ", " + m2 + "}");                }            }            // 就是往request域中缓存url中解析出来的参数,mediaType等,这边RequestMappingHandlerMapping也覆写了一下            handleMatch(bestMatch.mapping, lookupPath, request);            return bestMatch.handlerMethod;        }        else {            // RequestMappingHandlerMapping            return handleNoMatch(handlerMethods.keySet(), lookupPath, request);        }    }}
复制代码

 

// AbstractHandlerMethodMapping

查找具体符合条件的RequestCondition

复制代码
 1 package org.springframework.web.servlet.handler; 2 public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMapping implements InitializingBean { 3  4     private void addMatchingMappings(Collection<T> mappings, List<Match> matches, HttpServletRequest request) { 5         for (T mapping : mappings) { 6             T match = getMatchingMapping(mapping, request); 7             if (match != null) { 8                 matches.add(new Match(match, handlerMethods.get(mapping))); 9             }10         }11     }
复制代码

 

// AbstractHandlerMethodMapping

复制代码
1     /** 2      * Check if a mapping matches the current request and return a (potentially3      * new) mapping with conditions relevant to the current request.4      * @param mapping the mapping to get a match for5      * @param request the current HTTP servlet request6      * @return the match, or {@code null} if the mapping doesn't match7      */8     protected abstract T getMatchingMapping(T mapping, HttpServletRequest request);
复制代码

 

我们来看看RequestMappingInfoHandlerMapping中的实现,从RequestMappingInfo中查找符合的RequestCondition

// RequestMappingInfoHandlerMapping

复制代码
 1     /** 2      * Check if the given RequestMappingInfo matches the current request and 3      * return a (potentially new) instance with conditions that match the 4      * current request -- for example with a subset of URL patterns. 5      * @return an info in case of a match; or {@code null} otherwise. 6      */ 7     @Override 8     protected RequestMappingInfo getMatchingMapping(RequestMappingInfo info, HttpServletRequest request) { 9         return info.getMatchingCondition(request);10     }
复制代码

 

// AbstractHandlerMethodMapping

复制代码
1     /**2      * Invoked when a matching mapping is found.3      * @param mapping the matching mapping4      * @param lookupPath mapping lookup path within the current servlet mapping5      * @param request the current request6      */7     protected void handleMatch(T mapping, String lookupPath, HttpServletRequest request) {8         request.setAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE, lookupPath);9     }
复制代码

 

RequestMappingInfoHandlerMapping中又对其进行了覆写,具体是干啥用的,等看了HandlerAdaptor再说吧

复制代码
 1     /** 2      * Expose URI template variables, matrix variables, and producible media types in the request. 3      * @see HandlerMapping#URI_TEMPLATE_VARIABLES_ATTRIBUTE 4      * @see HandlerMapping#MATRIX_VARIABLES_ATTRIBUTE 5      * @see HandlerMapping#PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE 6      */ 7     @Override 8     protected void handleMatch(RequestMappingInfo info, String lookupPath, HttpServletRequest request) { 9         super.handleMatch(info, lookupPath, request);10 11         Set<String> patterns = info.getPatternsCondition().getPatterns();12         String bestPattern = patterns.isEmpty() ? lookupPath : patterns.iterator().next();13         request.setAttribute(BEST_MATCHING_PATTERN_ATTRIBUTE, bestPattern);14 15         Map<String, String> uriVariables = getPathMatcher().extractUriTemplateVariables(bestPattern, lookupPath);16         Map<String, String> decodedUriVariables = getUrlPathHelper().decodePathVariables(request, uriVariables);17         request.setAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, decodedUriVariables);18 19         if (isMatrixVariableContentAvailable()) {20             request.setAttribute(HandlerMapping.MATRIX_VARIABLES_ATTRIBUTE, extractMatrixVariables(request, uriVariables));21         }22 23         if (!info.getProducesCondition().getProducibleMediaTypes().isEmpty()) {24             Set<MediaType> mediaTypes = info.getProducesCondition().getProducibleMediaTypes();25             request.setAttribute(PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE, mediaTypes);26         }27     }
复制代码

 

 

复制代码
 1     /** 2      * Invoked when no matching mapping is not found. 3      * @param mappings all registered mappings 4      * @param lookupPath mapping lookup path within the current servlet mapping 5      * @param request the current request 6      * @throws ServletException in case of errors 7      */ 8     protected HandlerMethod handleNoMatch(Set<T> mappings, String lookupPath, HttpServletRequest request) 9             throws Exception {10 11         return null;12     }
复制代码

RequestMappingInfoHandlerMapping,覆写,不死心,再匹配一次

// RequestMappingInfoHandlerMapping

复制代码
 1     /** 2      * Iterate all RequestMappingInfos once again, look if any match by URL at 3      * least and raise exceptions accordingly. 4      * @throws HttpRequestMethodNotSupportedException if there are matches by URL 5      * but not by HTTP method 6      * @throws HttpMediaTypeNotAcceptableException if there are matches by URL 7      * but not by consumable/producible media types 8      */ 9     @Override10     protected HandlerMethod handleNoMatch(Set<RequestMappingInfo> requestMappingInfos,11             String lookupPath, HttpServletRequest request) throws ServletException {12 13         Set<String> allowedMethods = new LinkedHashSet<String>(4);14 15         Set<RequestMappingInfo> patternMatches = new HashSet<RequestMappingInfo>();16         Set<RequestMappingInfo> patternAndMethodMatches = new HashSet<RequestMappingInfo>();17 18         for (RequestMappingInfo info : requestMappingInfos) {19             if (info.getPatternsCondition().getMatchingCondition(request) != null) {20                 patternMatches.add(info);21                 if (info.getMethodsCondition().getMatchingCondition(request) != null) {22                     patternAndMethodMatches.add(info);23                 }24                 else {25                     for (RequestMethod method : info.getMethodsCondition().getMethods()) {26                         allowedMethods.add(method.name());27                     }28                 }29             }30         }31 32         if (patternMatches.isEmpty()) {33             return null;34         }35         else if (patternAndMethodMatches.isEmpty() && !allowedMethods.isEmpty()) {36             throw new HttpRequestMethodNotSupportedException(request.getMethod(), allowedMethods);37         }38 39         Set<MediaType> consumableMediaTypes;40         Set<MediaType> producibleMediaTypes;41         Set<String> paramConditions;42 43         if (patternAndMethodMatches.isEmpty()) {44             consumableMediaTypes = getConsumableMediaTypes(request, patternMatches);45             producibleMediaTypes = getProducibleMediaTypes(request, patternMatches);46             paramConditions = getRequestParams(request, patternMatches);47         }48         else {49             consumableMediaTypes = getConsumableMediaTypes(request, patternAndMethodMatches);50             producibleMediaTypes = getProducibleMediaTypes(request, patternAndMethodMatches);51             paramConditions = getRequestParams(request, patternAndMethodMatches);52         }53 54         if (!consumableMediaTypes.isEmpty()) {55             MediaType contentType = null;56             if (StringUtils.hasLength(request.getContentType())) {57                 try {58                     contentType = MediaType.parseMediaType(request.getContentType());59                 }60                 catch (IllegalArgumentException ex) {61                     throw new HttpMediaTypeNotSupportedException(ex.getMessage());62                 }63             }64             throw new HttpMediaTypeNotSupportedException(contentType, new ArrayList<MediaType>(consumableMediaTypes));65         }66         else if (!producibleMediaTypes.isEmpty()) {67             throw new HttpMediaTypeNotAcceptableException(new ArrayList<MediaType>(producibleMediaTypes));68         }69         else if (!CollectionUtils.isEmpty(paramConditions)) {70             String[] params = paramConditions.toArray(new String[paramConditions.size()]);71             throw new UnsatisfiedServletRequestParameterException(params, request.getParameterMap());72         }73         else {74             return null;75         }76     }
复制代码
0 0