SpringMVC源码解读
来源:互联网 发布:淘宝条形码是什么意思 编辑:程序博客网 时间:2024/04/29 15:14
SpringMVC源码解读 - HandlerMapping - RequestMappingHandlerMapping请求分发
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 }
- SpringMVC源码解读
- SpringMVC源码解读
- springmvc基本配置及相关源码解读
- SpringMVC源码解读 - HandlerMapping - RequestMappingHandlerMapping初始化
- SpringMVC源码之解读DispatcherServlet初始化流程
- SpringMVC工作原理解读--DispatcherServlet类源码解读(初级)
- 源码解读
- SpringMVC工作原理解读
- springMVC常用注解解读
- SpringMVC 配置文件以及解读
- springMVC常用注解解读
- SpringMVC HandlerMethodReturnValueHandler解读
- SpringMVC HandlerMethodArgumentResolver解读
- 源码解读之Intent解读
- [源码解读] FastClick.js源码解读
- springmvc异常信息的解读
- 【springmvc解读】<mvc:annotation-driven/>
- SpringMVC之web.xml解读
- 数据库的锁
- 【Opencv】图像扫描
- [Google EarlGrey] 0x00 安装及运行
- 不好意思,好久没更了。
- linux route命令详解
- SpringMVC源码解读
- hdu3416Marriage Match IV
- Block实现原理
- RunTime
- 使用pgpool-ii 搭建postgresql 高可用、负载均衡架构
- linux实战(十)----shell监控tomcat服务是否正常----综合运用
- poj 1054
- Git alias
- 经典数据挖掘算法(介绍了包括18大数据挖掘在内的多种经典数据挖掘算法)