HandlerMapping之RequestMappingHandlerMapping获取Handler

一、HandlerMapping类图


image.png

 

 

二、根据请求获取 HandlerExecutionChain

2.1 获取HandlerMethod流程

(1) 根据请求URL获取直接匹配的List<RequestMappingInfo>作为候选,如果没有则取所有的RequestMappingInfo作为候选,遍历候选的RequestMappingInfo,调用RequestMappingInfo#

getMatchingCondition方法(返回不为NULL则匹配),获取匹配的List<RequestMappingInfo>。可以扩展实现自定义匹配规则,传送门:2.1.3

(2) 如果没有匹配的RequestMappingInfo,按照具体不匹配原因抛出对应异常,比如:请求方法不匹配、请求参数类型不匹配、响应类型不匹配、方法参数缺失等

(3) 如果有多个匹配的RequestMappingInfo,OPTION请求则会直接返回,否则找出最匹配的RequestMappingInfo,如果有多个匹配度相同的RequestMappingInfo则抛出异常。

 

2.2 AbstractHandlerMapping

2.2.1 获取请求对应的HandlerExecutionChain getHandler

public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {

 // 查找给定请求的Handler,如果未找到特定Handler,则返回{@code null}。如果返回{@code null}值,则使用默认Handler。留给子类实现,传送门:3.3.1

 Object handler = getHandlerInternal(request);

 if (handler == null) {

  handler = getDefaultHandler();

 }

 if (handler == null) {

  return null;

 }

 

 if (handler instanceof String) {

  String handlerName = (String) handler;

  handler = obtainApplicationContext().getBean(handlerName);

 }

 

 // handler和interceptor(匹配的MappedInterceptor)封装为HandlerExecutionChain 

 HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);

 

 if (logger.isTraceEnabled()) {

  logger.trace("Mapped to " + handler);

 }

 else if (logger.isDebugEnabled() && !request.getDispatcherType().equals(DispatcherType.ASYNC)) {

  logger.debug("Mapped to " + executionChain.getHandler());

 }

 

 if (CorsUtils.isCorsRequest(request)) {

  // 全剧跨域配置

  CorsConfiguration globalConfig = this.corsConfigurationSource.getCorsConfiguration(request);

  // 匹配请求的跨域配置:如果handler是CorsConfigurationSource,获取request的跨域配置

  CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);

 // 全剧跨域配置 + 匹配请求的跨域配置

  CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);

  executionChain = getCorsHandlerExecutionChain(request, executionChain, config);

 }

 

 return executionChain;

}

 

2.2.2 封装Handler和请求对应的拦截器链 getHandlerExecutionChain

// handler和interceptor(匹配的MappedInterceptor)封装为HandlerExecutionChain

protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {

 HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?

   (HandlerExecutionChain) handler : new HandlerExecutionChain(handler));

 

 String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);

 for (HandlerInterceptor interceptor : this.adaptedInterceptors) {

  if (interceptor instanceof MappedInterceptor) {

   MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;

   if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {

    chain.addInterceptor(mappedInterceptor.getInterceptor());

   }

  }

  else {

   chain.addInterceptor(interceptor);

  }

 }

 return chain;

}

 

2.2.3 获取请求对应的跨域配置 getCorsConfiguration

// 如果handler是CorsConfigurationSource,获取request的跨域配置

protected CorsConfiguration getCorsConfiguration(Object handler, HttpServletRequest request) {

 Object resolvedHandler = handler;

 if (handler instanceof HandlerExecutionChain) {

  resolvedHandler = ((HandlerExecutionChain) handler).getHandler();

 }

 if (resolvedHandler instanceof CorsConfigurationSource) {

  return ((CorsConfigurationSource) resolvedHandler).getCorsConfiguration(request);

 }

 return null;

}

 

2.2.4 生成带跨域配置的HandlerExecutionChain getCorsHandlerExecutionChain

protected HandlerExecutionChain getCorsHandlerExecutionChain(HttpServletRequest request,

  HandlerExecutionChain chain, @Nullable CorsConfiguration config) {

 

 if (CorsUtils.isPreFlightRequest(request)) {

  HandlerInterceptor[] interceptors = chain.getInterceptors();

  chain = new HandlerExecutionChain(new PreFlightHandler(config), interceptors);

 }

 else {

  chain.addInterceptor(new CorsInterceptor(config));

 }

 return chain;

}

 

2.3 AbstractHandlerMethodMapping

2.3.1 获取请求对应的HandlerMethod getHandlerInternal

protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {

 String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);

 // this.mappingRegistry初始化时注册RequestMappingInfo 传送门:2.1.2.6、2.1.2.7

 this.mappingRegistry.acquireReadLock();

 try {

  HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);

  return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);

 }

 finally {

  this.mappingRegistry.releaseReadLock();

 }

}

 

2.3.2 查找匹配请求的HandlerMethod lookupHandlerMethod

protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {

 // Match封装了HandlerMethod和RequestMappingInfo

 List<Match> matches = new ArrayList<>();

 // 根据请求URL获取直接匹配的List<RequestMappingInfo>

 List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);

 if (directPathMatches != null) {

  // 获取匹配请求的处理方法:调用RequestMappingInfo#getMatchingCondition返回不为NULL则匹配

  addMatchingMappings(directPathMatches, matches, request);

 }

 if (matches.isEmpty()) {

  // 除了浏览所有mappings外别无选择。this.mappingRegistry.getMappings().keySet()获取所有的RequestMappingInfo,遍历找到匹配的处理方法

  addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request);

 }

 

 if (!matches.isEmpty()) {

  // 由子类实现,getMappingComparator 获取RequestMappingInfo比较器

  Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));

  matches.sort(comparator);

  Match bestMatch = matches.get(0);

  if (matches.size() > 1) {

   if (logger.isTraceEnabled()) {

    logger.trace(matches.size() + " matching mappings: " + matches);

   }

   // OPTION请求直接返回

   if (CorsUtils.isPreFlightRequest(request)) {

    return PREFLIGHT_AMBIGUOUS_MATCH;

   }

   Match secondBestMatch = matches.get(1);

   // 有多个匹配度相同的方法,抛出异常

   if (comparator.compare(bestMatch, secondBestMatch) == 0) {

    Method m1 = bestMatch.handlerMethod.getMethod();

    Method m2 = secondBestMatch.handlerMethod.getMethod();

    String uri = request.getRequestURI();

    throw new IllegalStateException(

      "Ambiguous handler methods mapped for '" + uri + "': {" + m1 + ", " + m2 + "}");

   }

  }

 

  // 在请求中保存最匹配的处理方法

  request.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, bestMatch.handlerMethod);

  // 由子类实现:在请求中公开URI模板变量,矩阵变量和可生产的媒体类型,在请求中保存了一些属性

  handleMatch(bestMatch.mapping, lookupPath, request);

  return bestMatch.handlerMethod;

 }

 else {

  return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);

 }

}

 

2.3.3 获取匹配请求的HandlerMethod addMatchingMappings

private void addMatchingMappings(Collection<T> mappings, List<Match> matches, HttpServletRequest request) {

 for (T mapping : mappings) {

  // 由子类实现,检查给定的RequestMappingInfo是否与当前请求匹配,调用RequestMappingInfo#getMatchingCondition

  T match = getMatchingMapping(mapping, request);

  if (match != null) {

   matches.add(new Match(match, this.mappingRegistry.getMappings().get(mapping)));

  }

 }

}

 

2.4 RequestMappingInfoHandlerMapping

2.4.1 检查给定的RequestMappingInfo是否与当前请求匹配 getMatchingMapping

// 检查给定的RequestMappingInfo是否与当前请求匹配,并返回一个(可能是新的)实例,该实例具有与当前请求匹配的条件-例如带有URL模式的子集。

protected RequestMappingInfo getMatchingMapping(RequestMappingInfo info, HttpServletRequest request) {

 return info.getMatchingCondition(request);

}

 

2.4.2 匹配当前请求设置属性 handleMatch

// 在请求中公开URI模板变量,矩阵变量和可生产的媒体类型

protected void handleMatch(RequestMappingInfo info, String lookupPath, HttpServletRequest request) {

 super.handleMatch(info, lookupPath, request);

 

 String bestPattern;

 Map<String, String> uriVariables;

 

 Set<String> patterns = info.getPatternsCondition().getPatterns();

 if (patterns.isEmpty()) {

  bestPattern = lookupPath;

  uriVariables = Collections.emptyMap();

 }

 else {

  bestPattern = patterns.iterator().next();

  uriVariables = getPathMatcher().extractUriTemplateVariables(bestPattern, lookupPath);

 }

 

 request.setAttribute(BEST_MATCHING_PATTERN_ATTRIBUTE, bestPattern);

 

 if (isMatrixVariableContentAvailable()) {

  Map<String, MultiValueMap<String, String>> matrixVars = extractMatrixVariables(request, uriVariables);

  request.setAttribute(HandlerMapping.MATRIX_VARIABLES_ATTRIBUTE, matrixVars);

 }

 

 Map<String, String> decodedUriVariables = getUrlPathHelper().decodePathVariables(request, uriVariables);

 request.setAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, decodedUriVariables);

 

 if (!info.getProducesCondition().getProducibleMediaTypes().isEmpty()) {

  Set<MediaType> mediaTypes = info.getProducesCondition().getProducibleMediaTypes();

  request.setAttribute(PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE, mediaTypes);

 }

}

 

2.4.3 针对不匹配请求返回具体异常 handleNoMatch

protected HandlerMethod handleNoMatch(

  Set<RequestMappingInfo> infos, String lookupPath, HttpServletRequest request) throws ServletException {

 

 PartialMatchHelper helper = new PartialMatchHelper(infos, request);

 if (helper.isEmpty()) {

  return null;

 }

 

 if (helper.hasMethodsMismatch()) {

  Set<String> methods = helper.getAllowedMethods();

  if (HttpMethod.OPTIONS.matches(request.getMethod())) {

   HttpOptionsHandler handler = new HttpOptionsHandler(methods);

   return new HandlerMethod(handler, HTTP_OPTIONS_HANDLE_METHOD);

  }

 

   // 请求处理程序不支持特定请求方法时引发的异常

  throw new HttpRequestMethodNotSupportedException(request.getMethod(), methods);

 }

 

 if (helper.hasConsumesMismatch()) {

  Set<MediaType> mediaTypes = helper.getConsumableMediaTypes();

  MediaType contentType = null;

  if (StringUtils.hasLength(request.getContentType())) {

   try {

    contentType = MediaType.parseMediaType(request.getContentType());

   }

   catch (InvalidMediaTypeException ex) {

    throw new HttpMediaTypeNotSupportedException(ex.getMessage());

   }

  }

   // 当客户端POST,PUT或PATCH的内容不受请求处理程序支持时,抛出此异常

  throw new HttpMediaTypeNotSupportedException(contentType, new ArrayList<>(mediaTypes));

 }

 

 if (helper.hasProducesMismatch()) {

  Set<MediaType> mediaTypes = helper.getProducibleMediaTypes();

  // 当请求处理程序无法生成客户端可接受的响应时引发的异常

  throw new HttpMediaTypeNotAcceptableException(new ArrayList<>(mediaTypes));

 }

 

 if (helper.hasParamsMismatch()) {

  List<String[]> conditions = helper.getParamConditions();

   // {@link ServletRequestBindingException}子类,指示不满意的参数条件,通常使用{@code @Controller}类型级别的{@code @RequestMapping} 注释表示。

  throw new UnsatisfiedServletRequestParameterException(conditions, request.getParameterMap());

 }

 

 return null;

}

 

三、RequestMappingInfo

3.1 检查给定的RequestMappingInfo是否与当前请求匹配 getMatchingCondition

public RequestMappingInfo getMatchingCondition(HttpServletRequest request) {

 RequestMethodsRequestCondition methods = this.methodsCondition.getMatchingCondition(request);

 if (methods == null) {

  return null;

 }

 ParamsRequestCondition params = this.paramsCondition.getMatchingCondition(request);

 if (params == null) {

  return null;

 }

 HeadersRequestCondition headers = this.headersCondition.getMatchingCondition(request);

 if (headers == null) {

  return null;

 }

 ConsumesRequestCondition consumes = this.consumesCondition.getMatchingCondition(request);

 if (consumes == null) {

  return null;

 }

 ProducesRequestCondition produces = this.producesCondition.getMatchingCondition(request);

 if (produces == null) {

  return null;

 }

 PatternsRequestCondition patterns = this.patternsCondition.getMatchingCondition(request);

 if (patterns == null) {

  return null;

 }

 

 // 自定义匹配规则 传送门:2.2.3

 RequestConditionHolder custom = this.customConditionHolder.getMatchingCondition(request);

 if (custom == null) {

  return null;

 }

 

 return new RequestMappingInfo(this.name, patterns,

   methods, params, headers, consumes, produces, custom.getCondition());

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值