深入理解RequestMappingHandlerMapping设计思想

简介

本文从类的设计角度分析SpringMVC从RequestMappingHandlerMapping获取handler的整体流程,分析了RequestMappingHandlerMapping及其父类之间的关系。

getHandler干了什么

getHandler主要干下面三件事情:

  1. 根据request找到handler
  2. 根据request找到handlerInterceptor
  3. 把handler和handlerInterceptor一起放到一个HandlerExecutionChain里面,返回这个HandlerExecutionChain。

在开始看代码之前先了解一下HandlerExecutionChain是个什么东西

public class HandlerExecutionChain {

   private final Object handler;

   @Nullable
   private HandlerInterceptor[] interceptors;

   @Nullable
   private List<HandlerInterceptor> interceptorList;
}

其实就是handler+HandlerInterceptor列表

那handler又是什么东西?注意到它的类型是Object,在RequestMappingHandlerMapping中它就是HandlerMethod。

public class HandlerMethod {

   private final Object bean;

   @Nullable
   private final BeanFactory beanFactory;

   private final Class<?> beanType;

   private final Method method;

   private final Method bridgedMethod;

   private final MethodParameter[] parameters;

   @Nullable
   private HttpStatus responseStatus;

   @Nullable
   private String responseStatusReason;

   @Nullable
   private HandlerMethod resolvedFromHandlerMethod;
}

HandlerMethod包含了处理 的方法的各种信息。

继承关系

先看一下继承关系

在这里插入图片描述

AbstractHandlerMapping主要实现找handlerInterceptor,子类实现找handler。

我们先从AbstractHandlerMapping开始分析。

AbstractHandlerMapping

先看最重要的方法getHandler,这是dispatcherServlet调用HandlerMapping的入口。

主逻辑
// AbstractHandlerMapping
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
   // 子类实现
   Object handler = getHandlerInternal(request);
   // hander相关的一些判断操作
   // 当前类实现,获得handlerInterceptor,组合成HandlerExecutionChain
   HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);

   // cors相关
   if (hasCorsConfigurationSource(handler) || CorsUtils.isPreFlightRequest(request)) {
       CorsConfiguration config = getCorsConfiguration(handler, request);
       if (getCorsConfigurationSource() != null) {
           CorsConfiguration globalConfig = getCorsConfigurationSource().getCorsConfiguration(request);
           config = (globalConfig != null ? globalConfig.combine(config) : config);
       }
       executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
	}
   return executionChain;
}

getHandlerInternal是子类实现的,这个之后再看,先分析getHandlerExecutionChain。

// AbstractHandlerMapping

// HandlerInterceptor列表
private final List<HandlerInterceptor> adaptedInterceptors = new ArrayList<>();

protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
   HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
         (HandlerExecutionChain) handler : new HandlerExecutionChain(handler));

   for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
      // 处理MappedInterceptor
      if (interceptor instanceof MappedInterceptor) {
         MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
         if (mappedInterceptor.matches(request)) {
            //把Interceptor加到HandlerExecutionChain里面
            chain.addInterceptor(mappedInterceptor.getInterceptor());
         }
      } else {
         // 处理普通Interceptor
         chain.addInterceptor(interceptor);
      }
   }
   return chain;
}

逻辑很简单,遍历this.adaptedInterceptors,把里面符合当前request的加到HandlerExecutionChain就好了。

唯一的问题就是这个this.adaptedInterceptors是怎么来的?

adaptedInterceptors初始化

答案就在initApplicationContext这个方法里,AbstractHandlerMapping继承了ApplicationObjectSupport,而 ApplicationObjectSupport实现了ApplicationContextAware,所以initApplicationContext这个方法会在bean初始化的时候被调用。

// AbstractHandlerMapping
protected void initApplicationContext() throws BeansException {
    // 空方法
   extendInterceptors(this.interceptors);
    // 找所有的MappedInterceptors,放到this.adaptedInterceptors里面
   detectMappedInterceptors(this.adaptedInterceptors);
    // 初始化Interceptors
   initInterceptors();
}

// 就是按类查找
protected void detectMappedInterceptors(List<HandlerInterceptor> mappedInterceptors) {
		mappedInterceptors.addAll(BeanFactoryUtils.beansOfTypeIncludingAncestors(
				obtainApplicationContext(), MappedInterceptor.class, true, false).values());
}

// 把interceptors列表中的interceptor做个类型转换,然后放到adaptedInterceptors列表中
protected void initInterceptors() {
   if (!this.interceptors.isEmpty()) {
      for (int i = 0; i < this.interceptors.size(); i++) {
         Object interceptor = this.interceptors.get(i);
         if (interceptor == null) {
            throw new IllegalArgumentException("Entry number " + i + " in interceptors array is null");
         }
         this.adaptedInterceptors.add(adaptInterceptor(interceptor));
      }
   }
}

上面找的是所有的MappedInterceptor,它和普通的Interceptor的关系是什么?

MappedInterceptor和Interceptor的关系

从xml配置文件看,它们的关系就是 < mvc:interceptor > 整体 和 MyInterceptor 的关系

<mvc:interceptors>
    <mvc:interceptor>
        <mvc:mapping path="/abc/**" />
        <mvc:exclude-mapping path="/xyz//*" />
        <bean class="com.a.b.c.MyInterceptor" />
    </mvc:interceptor>
</mvc:interceptors>

从代码中可以发现MappedInterceptor里面有具体的interceptor还有一些匹配路径相关的东西。

public final class MappedInterceptor implements HandlerInterceptor {

   private static PathMatcher defaultPathMatcher = new AntPathMatcher();

   @Nullable
   private final PathPattern[] includePatterns;

   @Nullable
   private final PathPattern[] excludePatterns;

   private PathMatcher pathMatcher = defaultPathMatcher;

   private final HandlerInterceptor interceptor;
}

AbstractHandlerMapping就分析完了,接下去看AbstractHandlerMethodMapping

AbstractHandlerMethodMapping

从AbstractHandlerMapping留给子类的getHandlerInternal开始分析

// AbstractHandlerMethodMapping

// 存储mapping和HandlerMethod的映射,mapping包含了匹配某个handler method需要的条件。
// 通俗的说mapping就是用来描述@RequestMapping里面的各种条件
private final MappingRegistry mappingRegistry = new MappingRegistry();

protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
    // 从request获取路径
   String lookupPath = initLookupPath(request);
    // mappingRegistry上锁
   this.mappingRegistry.acquireReadLock();
   try {
       // 从mappingRegistry里面找到handlerMethod
      HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
      return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
   }
   finally {
      this.mappingRegistry.releaseReadLock();
   }
}

接下来先来认识一下MappingRegistry。

T就表示mapping的类型,具体是RequestMappingInfo,在其子类RequestMappingInfoHandlerMapping中定义。

class MappingRegistry {
    // 通过@RequestMapping里面的条件,得到各种映射信息,具体初始化位置见MappingRegistry初始化

   private final Map<T, MappingRegistration<T>> registry = new HashMap<>();

   private final Map<T, HandlerMethod> mappingLookup = new LinkedHashMap<>();

   private final MultiValueMap<String, T> urlLookup = new LinkedMultiValueMap<>();

   private final Map<String, List<HandlerMethod>> nameLookup = new ConcurrentHashMap<>();

   private final Map<HandlerMethod, CorsConfiguration> corsLookup = new ConcurrentHashMap<>();

   private final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
}
lookupHandlerMethod
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
   List<Match> matches = new ArrayList<>();
   // 根据url找所有的mapping
   List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
   if (directPathMatches != null) {
      // 遍历根据url找到的所有的mapping,找和当前request匹配的,存到matches里面
      addMatchingMappings(directPathMatches, matches, request);
   }
   if (matches.isEmpty()) {
      // No choice but to go through all mappings...
      addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request);
   }

   if (!matches.isEmpty()) {
      Match bestMatch = matches.get(0);
      // 处理匹配到好几个的情况
      if (matches.size() > 1) {
          // 比较器留给子类实现
         Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
         matches.sort(comparator);
         bestMatch = matches.get(0);
         if (logger.isTraceEnabled()) {
            logger.trace(matches.size() + " matching mappings: " + matches);
         }
         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);
      // 有没有好奇过template uri里面的变量是怎么被传到入参里的
      // 里面会把template uri(比如hi/{id})中的值解析,以map的形式存到request里面,之后在绑定入参时就可以用了
      handleMatch(bestMatch.mapping, lookupPath, request);
      return bestMatch.handlerMethod;
   } else {
      return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
   }
}
private void addMatchingMappings(Collection<T> mappings, List<Match> matches, HttpServletRequest request) {
   for (T mapping : mappings) {
       // 留给子类实现
      T match = getMatchingMapping(mapping, request);
      if (match != null) {
         matches.add(new Match(match, this.mappingRegistry.getMappings().get(mapping)));
      }
   }
}
MappingRegistry初始化
// AbstractHandlerMethodMapping
@Override
public void afterPropertiesSet() {
   initHandlerMethods();
}

protected void initHandlerMethods() {
   // 获得所有的beanName
   for (String beanName : getCandidateBeanNames()) {
      if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
         // 找所有的handler method方法,如果有代理就找到代理方法,注册到mappingRegistry里面。
         processCandidateBean(beanName);
      }
   }
   // 没有逻辑代码,就log一下
   handlerMethodsInitialized(getHandlerMethods());
}

RequestMappingInfoHandlerMapping

继承AbstractHandlerMethodMapping,传入了具体的mapping类型:RequestMappingInfo。

public final class RequestMappingInfo implements RequestCondition<RequestMappingInfo> {
    private final String name;

	@Nullable
	private final PathPatternsRequestCondition pathPatternsCondition;

	@Nullable
	private final PatternsRequestCondition patternsCondition;

	private final RequestMethodsRequestCondition methodsCondition;

	private final ParamsRequestCondition paramsCondition;

	private final HeadersRequestCondition headersCondition;

	private final ConsumesRequestCondition consumesCondition;

	private final ProducesRequestCondition producesCondition;

	private final RequestConditionHolder customConditionHolder;

	private final int hashCode;
}

从父类AbstractHandlerMethodMapping留的getMatchingMapping和getMappingComparator方法开始分析。

getMatchingMapping
// RequestMappingInfoHandlerMapping
protected RequestMappingInfo getMatchingMapping(RequestMappingInfo info, HttpServletRequest request) {
   return info.getMatchingCondition(request);
}
// RequestMappingInfo
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;
   }
   PathPatternsRequestCondition pathPatterns = null;
   if (this.pathPatternsCondition != null) {
      pathPatterns = this.pathPatternsCondition.getMatchingCondition(request);
      if (pathPatterns == null) {
         return null;
      }
   }
   PatternsRequestCondition patterns = null;
   if (this.patternsCondition != null) {
      patterns = this.patternsCondition.getMatchingCondition(request);
      if (patterns == null) {
         return null;
      }
   }
   RequestConditionHolder custom = this.customConditionHolder.getMatchingCondition(request);
   if (custom == null) {
      return null;
   }
   return new RequestMappingInfo(
         this.name, pathPatterns, patterns, methods, params, headers, consumes, produces, custom);
}

上述代码就是从request中找到符合当前RequestMappingInfo的条件,然后根据这些条件重新创建一个RequestMappingInfo。

getMappingComparator
// RequestMappingInfoHandlerMapping
protected Comparator<RequestMappingInfo> getMappingComparator(final HttpServletRequest request) {
   return (info1, info2) -> info1.compareTo(info2, request);
}
// RequestMappingInfo
public int compareTo(RequestMappingInfo other, HttpServletRequest request) {
   int result;
   // Automatic vs explicit HTTP HEAD mapping
   if (HttpMethod.HEAD.matches(request.getMethod())) {
      result = this.methodsCondition.compareTo(other.getMethodsCondition(), request);
      if (result != 0) {
         return result;
      }
   }
   result = getActivePatternsCondition().compareTo(other.getActivePatternsCondition(), request);
   if (result != 0) {
      return result;
   }
   result = this.paramsCondition.compareTo(other.getParamsCondition(), request);
   if (result != 0) {
      return result;
   }
   result = this.headersCondition.compareTo(other.getHeadersCondition(), request);
   if (result != 0) {
      return result;
   }
   result = this.consumesCondition.compareTo(other.getConsumesCondition(), request);
   if (result != 0) {
      return result;
   }
   result = this.producesCondition.compareTo(other.getProducesCondition(), request);
   if (result != 0) {
      return result;
   }
   // Implicit (no method) vs explicit HTTP method mappings
   result = this.methodsCondition.compareTo(other.getMethodsCondition(), request);
   if (result != 0) {
      return result;
   }
   result = this.customConditionHolder.compareTo(other.customConditionHolder, request);
   if (result != 0) {
      return result;
   }
   return 0;
}

就是按照不同条件的优先级,进行比较。

RequestMappingHandlerMapping

在AbstractHandlerMethodMapping初始化过程中,调用了的processCandidateBean方法,其中用到的两个两个方法都是留给子类去实现的。

// AbstractHandlerMethodMapping
protected abstract boolean isHandler(Class<?> beanType);

@Nullable
protected abstract T getMappingForMethod(Method method, Class<?> handlerType);
// RequestMappingHandlerMapping
protected boolean isHandler(Class<?> beanType) {
    // 检查类上有没有Controller或者RequestMapping注解
   return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||
         AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
}

protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
    // 获取方法上的信息
   RequestMappingInfo info = createRequestMappingInfo(method);
   if (info != null) {
       // 获取类上的信息,合并
      RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType);
      if (typeInfo != null) {
         info = typeInfo.combine(info);
      }
      String prefix = getPathPrefix(handlerType);
      if (prefix != null) {
         info = RequestMappingInfo.paths(prefix).options(this.config).build().combine(info);
      }
   }
   return info;
}

总结

下面斜体部分表示具体功能由子类实现。

AbstractHandlerMapping
  1. 提供了getHandler这个主逻辑,getHandler主要分两部分:1. 获得Interceptors,2. 获得handler(具体逻辑子类实现)
  2. 完成获得Interceptors的步骤。
  3. 预留getHandlerInternal方法,由子类完成获得handler。
AbstractHandlerMethodMapping

这个类是获得method形式的handler的类,主要是有两部分,都是围绕MappingRegistry。MappingRegistry中mapping的具体类型是RequestMappingInfoHandlerMapping定义的。

初始化MappingRegistry

  1. 找到handler方法

  2. 获取handler方法的mapping,注册到MappingRegistry里面。

    这两部分的具体实现会涉及到RequestMappingHandlerMapping。

通过MappingRegistry获得handler

  1. 重载了AbstractHandlerMapping留的getHandlerInternal方法,返回一个HandlerMethod。这个过程主要分三部分:1. 获得mappings,2. 从mappings中找到和request匹配的(具体逻辑子类实现),3. 如果有好几个匹配的话需要排序(具体逻辑子类实现)。
  2. 预留getMatchingMapping方法,由RequestMappingInfoHandlerMapping重载,完成从mappings中找到和request匹配的。
  3. 预留getMappingComparator方法,由RequestMappingInfoHandlerMapping重载,完成mapping的排序。
RequestMappingInfoHandlerMapping
  1. 定义了AbstractHandlerMethodMapping中的mapping的具体类型RequestMappingInfo
  2. 重载了getMatchingMapping,实现从多个mappings中找到和request匹配的。
  3. 重载了getMappingComparator,实现mapping的排序。
RequestMappingHandlerMapping
  1. 重载AbstractHandlerMethodMapping初始化MappingRegistry过程中用到的两个函数isHandler和getMappingForMethod,实现从标了@RequestMapping的方法 到 mapping的转换。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值