1.1 获取执行调用链HandlerExecutionChain

本文详细介绍了Spring MVC中DispatcherServlet的doDispatch方法,重点关注如何获取执行调用链HandlerExecutionChain。从getHandler方法开始,经过AbstractHandlerMapping的getHandlerInternal和lookupHandlerMethod方法,解析出RequestMapping注解的Controller方法对象HandlerMethod。接着在getHandlerExecutionChain方法中,结合拦截器匹配,最终组装成HandlerExecutionChain,这个过程揭示了Spring MVC处理请求的内部逻辑。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

流程

查看doDispatch()方法, org.springframework.web.servlet.DispatcherServlet#doDispatch
获取调用链的核心方法为:

HandlerExecutionChain mappedHandler = null;
// ...中间省略一些代码...
mappedHandler = getHandler(processedRequest);

查看getHandler()方法, org.springframework.web.servlet.DispatcherServlet#getHandler
主要是通过循环handlerMappings, 查找出具体的handler, 并调用getHandler方法获取到HandlerExecutionChain, 这里的handlerMappings有三个初始值(spring容器初始化的时候就塞进去了), 分别是:
RequestMappingHandlerMapping, BeanNameUrlHandlerMapping, SimpleUrlHandlerMapping
我们使用的基本都是RequestMappingHandlerMapping

@Nullable
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
   if (this.handlerMappings != null) {
      for (HandlerMapping mapping : this.handlerMappings) {
         HandlerExecutionChain handler = mapping.getHandler(request);
         if (handler != null) {
            return handler;
         }
      }
   }
   return null;
}

查看mapping.getHandler()方法, org.springframework.web.servlet.handler.AbstractHandlerMapping#getHandler
关注第6行getHandlerInternal()获取了handler对象
关注第20行getHandlerExecutionChain()返回HandlerExecutionChain对象, 实际上就是把handler + interceptors整成一个HandlerExecutionChain对象

@Override
@Nullable
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {

   // 通过url获取HandlerMethod
   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 = obtainApplicationContext().getBean(handlerName);
   }

   // 返回拦截器调用链, 拦截器 + 具体的handler
   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);
      CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
      CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);
      executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
   }

   return executionChain;
}

查看第6行getHandlerInternal()方法, org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#getHandlerInternal
这个handler对象就是HandlerMethod, 即可以理解为在Controller中我们贴上@RequestMapping注解的方法对象(实际上再封装了一层)

@Override
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
   String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
   this.mappingRegistry.acquireReadLock();
   try {

      // 通过url获取HandlerMethod
      HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);

      // 构造一个有Handler的HandlerMethod, 将解析好的bean传进去, 后续可以通过method.invoke(bean, args), 已经具备bean了
      return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
   }
   finally {
      this.mappingRegistry.releaseReadLock();
   }
}

查看lookupHandlerMethod()方法, org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#lookupHandlerMethod
通过url找到urlLookup这个map中对应的handler, 然后根据一些匹配规则, 返回一个最优的 (urlLookup这个map中的键值对是在init初始化的时候, 通过反射解析放进去的), 到此为止可以知道: 我们可以通过url获取到具体的handlerMethod

@Nullable
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
   List<Match> matches = new ArrayList<>();
   
   // 通过url找到map中对应的handler, 然后根据一些匹配规则, 返回一个最优的
   List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
   if (directPathMatches != null) {
      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()) {
      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);
         }
         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);
      handleMatch(bestMatch.mapping, lookupPath, request);
      return bestMatch.handlerMethod;
   }
   else {
      return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
   }
}

再回过头来查看第20行getHandlerExecutionChain()方法, org.springframework.web.servlet.handler.AbstractHandlerMapping#getHandlerExecutionChain
找到所有匹配的拦截器, 然后加上handler拼装成一个HandlerExecutionChain对象并返回

protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
   
   // 创建一个HandlerExecutionChain对象
   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;
}

总结一下

HandlerExecutionChain
①通过url找到urlLookup这个map中的HandlerMethod对象
②通过拦截器对url进行匹配, 匹配到则添加该拦截器
③将HandlerMethod和HandlerInterceptor组装成HandlerExecutionChain

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值