SpringMVC源码分析(一)

本文深入探讨SpringMVC的请求处理流程,从DispatcherServlet的doGet方法开始,详细分析了从接收到HTTP请求到找到合适的HandlerMethod和bean实例的过程。涉及关键步骤包括processRequest、doService、doDispatch以及HandlerMapping的getHandlerInternal方法,揭示了SpringMVC如何根据URL匹配并创建执行链。

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

前言

      上一节,我们只是从总体上分析了springMVC的请求处理流程,但针对每一步的细节,具体还有哪些操作并没有说明,这一节,就请求过程中的很一步处理给出相应的分析说明。

源码分析

      假设在服务器部署了一个工程project,其中有一个业务是根据用户ID获取用户的详细信息,GET请求的URL是:http://localhost:8080/project/userController/getUserInfo?id=10001(不考虑有其它服务器转发),当服务器接收到浏览器发送的这个请求后,按httpServlet的规范,首先会找到DispatcherServlet中的doGet方法,发现此方法在DispatcherServlet的父类FrameworkServlet中

@Override
protected final void doGet(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {

   processRequest(request, response);
}

发现它直接委托给了processRequest去执行(其它的方法,如:doPost,doPut等也都是委托给这个方法去处理),我们来看看processRequest方法内容

protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {

   long startTime = System.currentTimeMillis();
   Throwable failureCause = null;
   //先取上一次的本地上下文,其实就是取Locale的信息,比如:国家,语言等等
   //主要是缓存,以便后面的恢复
   LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
   //新建一个LocaleContext
   LocaleContext localeContext = buildLocaleContext(request);
    //取上一个请求的RequestAttributes
   RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
   //新建一个RequestAttributes
   ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);
   //异步管理类,这个是内部使用的类,在这里不做分析
   WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
   asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());
    /**初始化ContextHolder,其实就是把当前的requestAttributes放到
    ThreadLocal中,方便在一些没有request作为参数的方法中,
    可以直接使用 RequestContextHolder.currentRequestAttributes()
    取到当前的request或response对象
    */
   initContextHolders(request, localeContext, requestAttributes);

   try {
       //重点,真正的处理交给了这个方法去执行
      doService(request, response);
   }
   catch (ServletException ex) {
      failureCause = ex;
      throw ex;
   }
   catch (IOException ex) {
      failureCause = ex;
      throw ex;
   }
   catch (Throwable ex) {
      failureCause = ex;
      throw new NestedServletException("Request processing failed", ex);
   }

   finally {
       //重置成上一个请求
      resetContextHolders(request, previousLocaleContext, previousAttributes);
      if (requestAttributes != null) {
         requestAttributes.requestCompleted();
      }

      if (logger.isDebugEnabled()) {
         if (failureCause != null) {
            this.logger.debug("Could not complete request", failureCause);
         }
         else {
            if (asyncManager.isConcurrentHandlingStarted()) {
               logger.debug("Leaving response open for concurrent processing");
            }
            else {
               this.logger.debug("Successfully completed request");
            }
         }
      }
        //发布事件
      publishRequestHandledEvent(request, response, startTime, failureCause);
   }
}

我们找到doService,发现它是一个FrameworkServlet的抽象方法,也就是说它希望子类DispatcherServlet去实现具体的处理过程

protected abstract void doService(HttpServletRequest request,
                                HttpServletResponse response) throws Exception;

在DispatcherServlet中的doService方法实现

@Override
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
   if (logger.isDebugEnabled()) {
      String resumed = WebAsyncUtils.getAsyncManager(request).hasConcurrentResult() ? " resumed" : "";
      logger.debug("DispatcherServlet with name '" + getServletName() + "'" + resumed +
            " processing " + request.getMethod() + " request for [" + getRequestUri(request) + "]");
   }

   // Keep a snapshot of the request attributes in case of an include,
   // to be able to restore the original attributes after the include.
   //如果此次请求中包含一个uri请求,就保存request的一个快照
   //方便恢复request的原始属性
   Map<String, Object> attributesSnapshot = null;
   if (WebUtils.isIncludeRequest(request)) {
      attributesSnapshot = new HashMap<String, Object>();
      Enumeration<?> attrNames = request.getAttributeNames();
      while (attrNames.hasMoreElements()) {
         String attrName = (String) attrNames.nextElement();
         if (this.cleanupAfterInclude || attrName.startsWith("org.springframework.web.servlet")) {
            attributesSnapshot.put(attrName, request.getAttribute(attrName));
         }
      }
   }

   // Make framework objects available to handlers and view objects.
   //设置一些全局参数给request
   request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
   request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
   request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
   request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());

   FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);
   if (inputFlashMap != null) {
      request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));
   }
   request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
   request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);

   try {
       //重点,主体处理又交给了这个方法
      doDispatch(request, response);
   }
   finally {
      if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
         // Restore the original attribute snapshot, in case of an include.
         if (attributesSnapshot != null) {
            restoreAttributesAfterInclude(request, attributesSnapshot);
         }
      }
   }
}

找到doDispatch方法,此时才是直接的开始

/**
 * Process the actual dispatching to the handler.
 * <p>The handler will be obtained by applying the servlet's HandlerMappings in order.
 * The HandlerAdapter will be obtained by querying the servlet's installed HandlerAdapters
 * to find the first that supports the handler class.
 * <p>All HTTP methods are handled by this method. It's up to HandlerAdapters or handlers
 * themselves to decide which methods are acceptable.
 * @param request current HTTP request
 * @param response current HTTP response
 * @throws Exception in case of any kind of processing failure
 */
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
   HttpServletRequest processedRequest = request;
   HandlerExecutionChain mappedHandler = null;
   boolean multipartRequestParsed = false;

   WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

   try {
      ModelAndView mv = null;
      Exception dispatchException = null;

      try {
          //检查是否是Multipart请求,比如:文件上传就是一个Multipart请求
          //否则返回原来的request
         processedRequest = checkMultipart(request);
         multipartRequestParsed = (processedRequest != request);

         // Determine handler for the current request.
         //根据request去handlerMapping映射中到对应的HandlerExecutionChain
         //
         mappedHandler = getHandler(processedRequest);
         if (mappedHandler == null || mappedHandler.getHandler() == null) {
           //如果没有找到,说明请求的地址错误
             noHandlerFound(processedRequest, response);
            return;
         }

         // Determine handler adapter for the current request.
         //取到执行链后,再去找对应的处理器的适配器
         HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

         // Process last-modified header, if supported by the handler.
         String method = request.getMethod();
         boolean isGet = "GET".equals(method);
         if (isGet || "HEAD".equals(method)) {
            long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
            if (logger.isDebugEnabled()) {
               logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
            }
            if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
               return;
            }
         }
        //执行链中的拦截器执行
         if (!mappedHandler.applyPreHandle(processedRequest, response)) {
            return;
         }

         // Actually invoke the handler.
         //交给适配器去解析参数等等并执行对应的方法,返回
         //ModelAndView
         mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

         if (asyncManager.isConcurrentHandlingStarted()) {
            return;
         }
         //如果没有view就给它一个默认的
         applyDefaultViewName(processedRequest, mv);
         //执行拦截器的postHandle
         mappedHandler.applyPostHandle(processedRequest, response, mv);
      }
      catch (Exception ex) {
         dispatchException = ex;
      }
      //处理返回结果,这里就是把Model填充到view中
      processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
   }
   catch (Exception ex) {
      triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
   }
   catch (Error err) {
      triggerAfterCompletionWithError(processedRequest, response, mappedHandler, err);
   }
   finally {
      if (asyncManager.isConcurrentHandlingStarted()) {
         // Instead of postHandle and afterCompletion
         if (mappedHandler != null) {
            mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
         }
      }
      else {
         // Clean up any resources used by a multipart request.
         if (multipartRequestParsed) {
            cleanupMultipart(processedRequest);
         }
      }
   }
}

checkMultipart处理的内容很简单,上面已经说明,我们来看看 getHandler(processedRequest)做了哪些事件?主要是遍历handlerMappings找到匹配的执行链

protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
   for (HandlerMapping hm : this.handlerMappings) {
      if (logger.isTraceEnabled()) {
         logger.trace(
               "Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");
      }
      HandlerExecutionChain handler = hm.getHandler(request);
      if (handler != null) {
         return handler;
      }
   }
   return null;
}

HandlerMapping中的getHandler方法

/**
 * Look up a handler for the given request, falling back to the default
 * handler if no specific one is found.
 * @param request current HTTP request
 * @return the corresponding handler instance, or the default handler
 * @see #getHandlerInternal
 */
@Override
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
   //委托给此方法去查找handler
   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 = getApplicationContext().getBean(handlerName);
   }

   HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
   if (CorsUtils.isCorsRequest(request)) {
      CorsConfiguration globalConfig = this.corsConfigSource.getCorsConfiguration(request);
      CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
      CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);
      executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
   }
   return executionChain;
}

进入到AbstractHandlerMethodMapping的getHandlerInternal方法,先从request获取到lookupPath,相当于上面的(userControoler/getUserInfo)

/**
 * Look up a handler method for the given request.
 */
@Override
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
   String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
   if (logger.isDebugEnabled()) {
      logger.debug("Looking up handler method for path " + lookupPath);
   }
   /**
   这里的mappingRegistry,其实就是一个映射关系注册中心,维护所有mapping与handlerMethod的映射关系
   为了提供并发访问,每次都是显示的获取锁,获取后再显示的释放锁
   
   */
   this.mappingRegistry.acquireReadLock();
   try {
       //获取handlerMethod,下面进行分析
      HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
      if (logger.isDebugEnabled()) {
         if (handlerMethod != null) {
            logger.debug("Returning handler method [" + handlerMethod + "]");
         }
         else {
            logger.debug("Did not find handler method for [" + lookupPath + "]");
         }
      }
      return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
   }
   finally {
      this.mappingRegistry.releaseReadLock();
   }
}
/**
 * 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>();
   //从mappingRegistry中的urllookup中获取RequestMappingInfo集合
   //其实,每一个requestMapping都会被封装成RequestMappingInfo
   List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
   if (directPathMatches != null) {
       //遍历所有的匹配的mappings(directPathMatches)
      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));
      Collections.sort(matches, comparator);
      if (logger.isTraceEnabled()) {
         logger.trace("Found " + matches.size() + " matching mapping(s) for [" +
               lookupPath + "] : " + matches);
      }
      //取最匹配的match
      Match bestMatch = matches.get(0);
      if (matches.size() > 1) {
         if (CorsUtils.isPreFlightRequest(request)) {
            return PREFLIGHT_AMBIGUOUS_MATCH;
         }
         //取第二匹配的
         Match secondBestMatch = matches.get(1);
         //如果两个相同,则springmvc也不知道哪个是用户需要的方法了
         //所以,不能存在相同的路径对应两个方法
         if (comparator.compare(bestMatch, secondBestMatch) == 0) {
            Method m1 = bestMatch.handlerMethod.getMethod();
            Method m2 = secondBestMatch.handlerMethod.getMethod();
            throw new IllegalStateException("Ambiguous handler methods mapped for HTTP path '" +
                  request.getRequestURL() + "': {" + m1 + ", " + m2 + "}");
         }
      }
      handleMatch(bestMatch.mapping, lookupPath, request);
      //返回最佳匹配的mapping对应的HandlerMethod
      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) {
       //找到匹配的mapping加入到matchs集合中
      T match = getMatchingMapping(mapping, request);
      if (match != null) {
         matches.add(new Match(match, this.mappingRegistry.getMappings().get(mapping)));
      }
   }
}

Match类的结构,它其实是AbstractHandlerMethodMapping的内部类

/**
 * A thin wrapper around a matched HandlerMethod and its mapping, for the purpose of
 * comparing the best match with a comparator in the context of the current request.
 */
private class Match {
//Match类是AbstractHandlerMethodMapping的内部类
   private final T mapping;

   private final HandlerMethod handlerMethod;

   public Match(T mapping, HandlerMethod handlerMethod) {
      this.mapping = mapping;
      this.handlerMethod = handlerMethod;
   }

   @Override
   public String toString() {
      return this.mapping.toString();
   }
}

再回到AbstractHandlerMethodMapping的getHandlerInternal方法中,接下来是判断handlerMethod是否为空,如果不为空则调用createWithResolvedBean()方法,这个方法的逻辑是如果当前handlerMethod中的bean只是名称时,那么通过beanFactory获得bean的实例,再次封装成HadnerMethod对象返回。这里的bean是指方法所在的类对象,例如:上述中的userController中的getUserInfo方法,getUserInfo就是handlerMethod而userController就是上面所说的bean。

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

再回到AbstractHandlerMapping的getHandler(HttpServletRequest request)方法,接下来就是执行

HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);

获取执行链,进入此方法,

protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
   //先判断是否是执行链对象,如果不是就把handler封装成一个执行链
   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执行链对象,返回到DispatcherServlet中。接下来就是需要获取执行适配器(管家)

总结

       重新回顾一下,在DispatcherServlet的doDispatch方法中,第一步是判断是否是Multipart请求,第二步就是获取执行链接对象mappedHandler。分析到此也只是完成这个方法的第二步,即通过请求的url找到对应的handlerMethod和bean对象,近而取得了执行链对象。为下一步的执行做准备。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值