SpringMVC源码分析(一)

前言

      上一节,我们只是从总体上分析了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 attributesSnapshot = null;
   if (WebUtils.isIncludeRequest(request)) {
      attributesSnapshot = new HashMap();
      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.
 * 

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. *

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 matches = new ArrayList();
   //从mappingRegistry中的urllookup中获取RequestMappingInfo集合
   //其实,每一个requestMapping都会被封装成RequestMappingInfo
   List 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 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 mappings, List 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对象,近而取得了执行链对象。为下一步的执行做准备。

 

你可能感兴趣的:(java框架)