Spring MVC 源码分析

226 阅读15分钟

基本流程

springmvc流程分析.png

源码分析

Servlet的生命周期方法

Servlet接口如下:

public interface Servlet {

    /**
     * Serrvlet初始化方法,Servlet对象创建之后调用
     */
    public void init(ServletConfig config) throws ServletException;
    
    /**
     * Servlet对象被`HTTP`请求访问时调用
     */
    public void service(ServletRequest req, ServletResponse res)
   throws ServletException, IOException;
   
   
    /**
     * 销毁方法
     */
    public void destroy();
}
  • init: Servlet对象创建之后调用
  • service: Servlet对象被HTTP请求访问时调用
  • destroy: Servlet对象销毁之前调用

DispatcherServlet继承体系

image.png

InitializingBean接口介绍

在我们介绍Spring源码分析的提到该接口,该接口会在bean实例化并且填充完属性之后,准备调用init-method初始化方法之前就会调用实现了InitializingBean接口的afterPropertiesSet方法。这部分可以查看Spring源码。

在下面我们在分析处理器映射器HandlerMapping和处理器适配器HandlerAdapter时,发现两者都实现了InitializingBean接口。

DispatcherServlet主流程

DispatcherServlet初始化流程

入口:GenericServlet#init(config)

image.png

接下来准备调用GenericServlet#init()方法了,不过该方法它没有实现,而是被子类HttpServletBean给覆盖了,我们直接看看HttpServletBean#init()方法吧。

/**
 * GenericServlet中的init方法真正调用子类HttpServletBean的init方法
 */
@Override
public final void init() throws ServletException {
   if (logger.isDebugEnabled()) {
      logger.debug("Initializing servlet '" + getServletName() + "'");
   }

   // Set bean properties from init parameters.
   PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
   if (!pvs.isEmpty()) {
      try {
         BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
         ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext());
         bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment()));
         initBeanWrapper(bw);
         bw.setPropertyValues(pvs, true);
      }
      catch (BeansException ex) {
         if (logger.isErrorEnabled()) {
            logger.error("Failed to set bean properties on servlet '" + getServletName() + "'", ex);
         }
         throw ex;
      }
   }

   // Let subclasses do whatever initialization they like.
   //真正调用该方法
   //接着调用子类FrameworkServlet中的initServletBean方法
   initServletBean();

   if (logger.isDebugEnabled()) {
      logger.debug("Servlet '" + getServletName() + "' configured successfully");
   }
}

接着查看上面代码中的initServletBean()方法,不过该方法需要去HttpServletBean的子类FrameworkServlet中去看看

/**
 * 真正调用该方法
 */
@Override
protected final void initServletBean() throws ServletException {
   getServletContext().log("Initializing Spring FrameworkServlet '" + getServletName() + "'");
   if (logger.isInfoEnabled()) {
      logger.info("FrameworkServlet '" + getServletName() + "': initialization started");
   }
   long startTime = System.currentTimeMillis();

   try {
      //重点 初始化Web环境中的Spring容器WebApplicationContext
      this.webApplicationContext = initWebApplicationContext();
      initFrameworkServlet();
   }
   catch (ServletException | RuntimeException ex) {
      logger.error("Context initialization failed", ex);
      throw ex;
   }

   if (logger.isInfoEnabled()) {
      long elapsedTime = System.currentTimeMillis() - startTime;
      logger.info("FrameworkServlet '" + getServletName() + "': initialization completed in " +
            elapsedTime + " ms");
   }
}

接着查看上面代码中的initWebApplicationContext()方法

/**
 * 初始化Web环境中的Spring容器WebApplicationContext
 */
protected WebApplicationContext initWebApplicationContext() {
   //父容器
   WebApplicationContext rootContext =
         WebApplicationContextUtils.getWebApplicationContext(getServletContext());
   //子容器
   WebApplicationContext wac = null;

   if (this.webApplicationContext != null) {
      // A context instance was injected at construction time -> use it
      wac = this.webApplicationContext;
      if (wac instanceof ConfigurableWebApplicationContext) {
         ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
         if (!cwac.isActive()) {
            // The context has not yet been refreshed -> provide services such as
            // setting the parent context, setting the application context id, etc
            if (cwac.getParent() == null) {
               // The context instance was injected without an explicit parent -> set
               // the root application context (if any; may be null) as the parent
               cwac.setParent(rootContext);
            }
            configureAndRefreshWebApplicationContext(cwac);
         }
      }
   }
   if (wac == null) {
      // No context instance was injected at construction time -> see if one
      // has been registered in the servlet context. If one exists, it is assumed
      // that the parent context (if any) has already been set and that the
      // user has performed any initialization such as setting the context id
      wac = findWebApplicationContext();
   }
   if (wac == null) {
      // No context instance is defined for this servlet -> create a local one
      wac = createWebApplicationContext(rootContext);
   }

   if (!this.refreshEventReceived) {
      // Either the context is not a ConfigurableApplicationContext with refresh
      // support or the context injected at construction time had already been
      // refreshed -> trigger initial onRefresh manually here.
      synchronized (this.onRefreshMonitor) {
         //刷新容器中的策略
         //重点,该方法用于创建Spring容器
         onRefresh(wac);
      }
   }

   if (this.publishContext) {
      // Publish the context as a servlet context attribute.
      String attrName = getServletContextAttributeName();
      //将Spring容器存入到ServletContext上下文
      getServletContext().setAttribute(attrName, wac);
      if (this.logger.isDebugEnabled()) {
         this.logger.debug("Published WebApplicationContext of servlet '" + getServletName() +
               "' as ServletContext attribute with name [" + attrName + "]");
      }
   }

   return wac;
}

上述代码主要根据springmvc.xml配置文件创建spring容器,onRefresh()方法是初始化一些默认组件,比如HandlerMapping组件中的(BeanNameURLHandlerMapping),但是该方法最终在DispatcherServlet中调用,我们进入这个方法看看。

/**
 * This implementation calls {@link #initStrategies}.
 */
@Override
protected void onRefresh(ApplicationContext context) {
   initStrategies(context);
}
/**
 * 初始化方法
 */
protected void initStrategies(ApplicationContext context) {
   initMultipartResolver(context);//初始化文件上传解析器
   initLocaleResolver(context);
   initThemeResolver(context);
   initHandlerMappings(context);//初始化处理器映射器
   initHandlerAdapters(context);//初始化处理器适配器
   initHandlerExceptionResolvers(context);
   initRequestToViewNameTranslator(context);
   initViewResolvers(context);//初始化视图解析器
   initFlashMapManager(context);
}

看到了这个地方,我想大家已经明白入门程序为什么没有配置三大组件,Spring容器中却依然有这些组件了吧。这个地方初始化了很多默认配置,我们随便找个initHandlerMapping来了解一下它们是怎么实现的吧

/**
 *
 */
private void initHandlerMappings(ApplicationContext context) {
   this.handlerMappings = null;

   if (this.detectAllHandlerMappings) {
      // Find all HandlerMappings in the ApplicationContext, including ancestor contexts.
      Map<String, HandlerMapping> matchingBeans =
            BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
      if (!matchingBeans.isEmpty()) {
         this.handlerMappings = new ArrayList<>(matchingBeans.values());
         // We keep HandlerMappings in sorted order.
         AnnotationAwareOrderComparator.sort(this.handlerMappings);
      }
   }
   else {
      try {
         HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);
         this.handlerMappings = Collections.singletonList(hm);
      }
      catch (NoSuchBeanDefinitionException ex) {
         // Ignore, we'll add a default HandlerMapping later.
      }
   }

   // Ensure we have at least one HandlerMapping, by registering
   // a default HandlerMapping if no other mappings are found.
   if (this.handlerMappings == null) {
      //重点
      this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
      if (logger.isDebugEnabled()) {
         logger.debug("No HandlerMappings found in servlet '" + getServletName() + "': using default");
      }
   }
}

上述代码中重点在getDefaultStrategies(context, HandlerMapping.class)方法,该方法获取默认的处理器解析器。接下来查看该方法,如下:

image.png

image.png

image.png 从上述截图,我们可以发现,defaultStrategies中的值就是从DispatcherServlet.properties中读取并且解析得到的,而该文件在如下包中。

image.png

该文件的内容如下:

# Default implementation classes for DispatcherServlet's strategy interfaces.
# Used as fallback when no matching beans are found in the DispatcherServlet context.
# Not meant to be customized by application developers.

org.springframework.web.servlet.LocaleResolver=org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver

org.springframework.web.servlet.ThemeResolver=org.springframework.web.servlet.theme.FixedThemeResolver

# 处理器映射器的所有实现类
org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\
   org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping

# 适配器处理器的所有实现类
org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\
   org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\
   org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter

org.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver,\
   org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver,\
   org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver

org.springframework.web.servlet.RequestToViewNameTranslator=org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator

# 视图解析器默认使用的实现类
org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver

org.springframework.web.servlet.FlashMapManager=org.springframework.web.servlet.support.SessionFlashMapManager

总结

DispatcherServlet初始化流程就是将DispatcherServlet.properties配置文件进行解析,得到默认的配置信息,之后创建出默认的处理器映射器集合,处理器适配器集合和视图解析器等等。至此,DispatcherServlet初始化工作就完成了。

DispatcherServlet核心处理流程

入口类:org.springframework.web.servlet.DispatcherServlet

该类的继承结构如下:

image.png 由继承结构图可知,DispatcherServlet,直接继承了FrameworkServlet,间接实现了Servlet接口。间接继承了HttpServletBean,,而类HttpServletBean是直接继承HttpServlet的。如下图所示

image.png

image.png

image.png

首先从父类FrameworkServletdoGetdoPost方法看起,如下图所示

/**
 * Delegate GET requests to processRequest/doService.
 * <p>Will also be invoked by HttpServlet's default implementation of {@code doHead},
 * with a {@code NoBodyResponse} that just captures the content length.
 * @see #doService
 * @see #doHead
 * 先看该方法,接着看该方法中的processRequest方法
 */
@Override
protected final void doGet(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {

   //重点
   processRequest(request, response);
}

/**
 * Delegate POST requests to {@link #processRequest}.
 * @see #doService
 */
@Override
protected final void doPost(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {
      
   //重点
   processRequest(request, response);
}


/**
 * Process this request, publishing an event regardless of the outcome.
 * <p>The actual event handling is performed by the abstract
 * {@link #doService} template method.
 *
 * 重点,真正调用该方法
 */
protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {

   long startTime = System.currentTimeMillis();
   Throwable failureCause = null;

   LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
   LocaleContext localeContext = buildLocaleContext(request);

   RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
   ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);

   WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
   asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());

   initContextHolders(request, localeContext, requestAttributes);

   try {
      //重点,该方法为抽象方法,所以调用子类DispatcherServlet中的doService方法
      doService(request, response);
   }
   catch (ServletException | 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);
   }
   
 
    /**
     * Subclasses must implement this method to do the work of request handling,
     * receiving a centralized callback for GET, POST, PUT and DELETE.
     * <p>The contract is essentially the same as that for the commonly overridden
     * {@code doGet} or {@code doPost} methods of HttpServlet.
     * <p>This class intercepts calls to ensure that exception handling and
     * event publication takes place.
     * @param request current HTTP request
     * @param response current HTTP response
     * @throws Exception in case of any kind of processing failure
     * @see javax.servlet.http.HttpServlet#doGet
     * @see javax.servlet.http.HttpServlet#doPost
     */
    protected abstract void doService(HttpServletRequest request, HttpServletResponse response)
          throws Exception;
}

不管是doGet还是doPost方法,最终都会调用processRequest方法,而在processRequest方法中核心代码逻辑是doService(request, response),但是该方法在父类FrameworkServlet中是一个抽象方法,真正实现在子类中【这里用到了MyBatis源码涉及的设计模式提到的适配器设计模式】。

接着重点查看子类DispatcherServlet中的doService方法,如下:

/**
 * Exposes the DispatcherServlet-specific request attributes and delegates to {@link #doDispatch}
 * for the actual dispatching.
 * 重点
 */
@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.
   Map<String, Object> 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(DEFAULT_STRATEGIES_PREFIX)) {
            attributesSnapshot.put(attrName, request.getAttribute(attrName));
         }
      }
   }

   // Make framework objects available to handlers and view objects.
   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());

   if (this.flashMapManager != null) {
      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(request, response)代码,接着查看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 {
         //处理文件上传的request请求
         processedRequest = checkMultipart(request);
         multipartRequestParsed = (processedRequest != request);

         // Determine handler for the current request.
         /**
          * 重点,点进去看看源码逻辑
          *
          * 通过处理器映射器HandlerMapping,获取handler处理器执行链,即HandlerExecutionChain对象
          * 该执行链封装了处理器即Handler对象和对应处理器的拦截器即HandlerInterceptor(可能有多个).
          * 需要注意的是@Controller注解的类,它不是我们这里要查找的处理器,我们要找的处理器是@RequestMapping对应的方法,
          * 这个方法会在
          *
          */
         mappedHandler = getHandler(processedRequest);
         if (mappedHandler == null) {
            noHandlerFound(processedRequest, response);
            return;
         }

         // Determine handler adapter for the current request.

         //重点,点进去看看源码逻辑
         //通过找到的Handler处理器,去匹配合适的处理器适配器HandlerAdapter
         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;
            }
         }

         //执行拦截器interceptor的preHandle方法
         if (!mappedHandler.applyPreHandle(processedRequest, response)) {
            return;
         }

         // Actually invoke the handler.

         //重点
         //通过处理器适配器,真正调用处理器方法
         //真正调用AbstractHandlerMethdAdapter类中的handle方法
         mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

         if (asyncManager.isConcurrentHandlingStarted()) {
            return;
         }

         //设置默认视图名称
         applyDefaultViewName(processedRequest, mv);
         //执行拦截器interceptor的postHandle方法
         mappedHandler.applyPostHandle(processedRequest, response, mv);
      }
      catch (Exception ex) {
         dispatchException = ex;
      }
      catch (Throwable err) {
         // As of 4.3, we're processing Errors thrown from handler methods as well,
         // making them available for @ExceptionHandler methods and other scenarios.
         dispatchException = new NestedServletException("Handler dispatch failed", err);
      }
      //重点,点进去看源码
      //处理调度结果(也就是ModelAndView对象)
      processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
   }
   catch (Exception ex) {
      //执行拦截器interceptor的afterCompletion方法
      triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
   }
   catch (Throwable err) {

      //执行拦截器interceptor的afterCompletion方法
      triggerAfterCompletion(processedRequest, response, mappedHandler,
            new NestedServletException("Handler processing failed", 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);
         }
      }
   }
}

doDispatch方法的流程如下:

未命名文件 (1).png

处理器映射器

注册流程

本章节主要是分析注解方式的处理器映射器: RequestMappingHandlerMapping:根据@RequestMapping注解查找处理器(HandlerMethod

由于RequestMappingHandlerMapping间接实现了InitializingBean,所以该对象在实例化并且填充属性之后,在调用初始化方法之前就会调用afterPropertiesSet方法。

分析入口RequestMappingHandlerMapping#afterPropertiesSet方法

image.png

接着查看AbstractHandlerMethodMappingafterPropertiesSet方法。

image.png

image.png

我们继续去看看detectHandlerMethods方法(核心处理方法)

/**
 * 重点
 * 从Controller或者RequestMapping注解的Bean中,找到所有的HnadlerMethod对象,并进行存储
 */
protected void detectHandlerMethods(Object handler) {
   //获取处理器类型
   Class<?> handlerType = (handler instanceof String ?
         obtainApplicationContext().getType((String) handler) : handler.getClass());

   if (handlerType != null) {
      //如果该类是通过cglib代理的代理类,则获取其父类类型,否则的话,直接返回该类
      Class<?> userType = ClassUtils.getUserClass(handlerType);
      /**
       * 存储Method方法和RequestMapping注解信息的映射关系(重点)
       * 该映射关系会解析成我们需要的其他两个映射关系
       * key是Controller类中的Method对象,value是RequestMappingInfo对象(即@RequestMapping注解中的属性信息)
       */
      Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
            (MethodIntrospector.MetadataLookup<T>) method -> {//此处是设置回调函数
               try {
                  //获取bean上面和method上面的RequestMapping注解信息,则装到RequestMappingInfo对象中
                  return getMappingForMethod(method, userType);
               }
               catch (Throwable ex) {
                  throw new IllegalStateException("Invalid mapping on handler class [" +
                        userType.getName() + "]: " + method, ex);
               }
            });
      if (logger.isDebugEnabled()) {
         logger.debug(methods.size() + " request handler methods found on " + userType + ": " + methods);
      }
      methods.forEach((method, mapping) -> {
         Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
         //注册HandlerMethod和RequestMappingInfo对象的关系
         //注册请求URL和RequestMappingInfo对象关系
         //重点
         registerHandlerMethod(handler, invocableMethod, mapping);
      });
   }
}

上面的方法处理逻辑主要分为两大步骤:

  • 映射MethodRequestMappingInfo的关系
  • 映射关系:RequestMappingInfoURLHandlerMethod的关系。

我们先看第一大步骤,也就是调用MethodIntrospectorselectMethods方法

image.png

接着我们去看一下MetadataLookup的匿名内部类实现中调用的getMappingForMethod方法是如何实现的?需要去RequestMappingHandlerMapping类中去查看该方法。

/**
 * 真正调用该方法
 * 获取bean上面和method上面的RequestMapping注解信息,则装到RequestMappingInfo对象中
 */
@Override
@Nullable
protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
   //从获取指定method对应的RequestMapping注解信息
   RequestMappingInfo info = createRequestMappingInfo(method);
   if (info != null) {
      //获取指定bean对应的RequestMapping注解信息
      RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType);
      if (typeInfo != null) {
         //将bean上面的RequestMapping信息和method上面的RequestMapping信息进行合并
         info = typeInfo.combine(info);
      }
   }
   return info;
}


@Nullable
private RequestMappingInfo createRequestMappingInfo(AnnotatedElement element) {
   //获取到@RequestMapping注解中配置的信息
   RequestMapping requestMapping = AnnotatedElementUtils.findMergedAnnotation(element, RequestMapping.class);
   RequestCondition<?> condition = (element instanceof Class ?
         getCustomTypeCondition((Class<?>) element) : getCustomMethodCondition((Method) element));
   //查看createRequestMappingInfo方法
   return (requestMapping != null ? createRequestMappingInfo(requestMapping, condition) : null);
}

image.png

至此第一大步骤我们阅读完了,接下来去看看第二大步骤,我们看看AbstractHandlerMethodMapping#registerHandlerMethod方法。

image.png

接下来,我们去看看register方法

image.png

至此处理器映射器的初始化流程就完成了。

处理流程

分析入口:DispatcherServlet#getHandler方法

image.png

接下来我们需要进入到具体的AbstractHandlerMapping#getHandler方法

image.png

接下来我们重点看看AbstractHandlerMethodMapping#getHandlerInternal方法。

image.png 接下来我们重点去看看lookupHandlerMethod方法(核心方法

image.png

我们继续去看看addMatchingMappings方法

image.png

接着去RequestMappingInfoHandlerMapping#getMatchingMapping方法

image.png

最后去RequestMappingInfo#getMatchingCondition方法

image.png

总结

如下图所示

image.png

该处理流程主要是通过URL匹配在初始化时对应存储的RequestMappingInfo,接着通过RequestMappingInfo找到对应的Method,最后封装成HandlerMethod,HandlerMethod类结构如下:

/**
 *
 * 注意:Controller类和其中的一个Method对象,组成了一个HnadlerMathod对象,该对象就是适配器去适配的Hadler处理器
 */
public class HandlerMethod {

   /** Logger that is available to subclasses */
   protected final Log logger = LogFactory.getLog(getClass());

   //该属性就是Controller类
   private final Object bean;

   @Nullable
   private final BeanFactory beanFactory;

   private final Class<?> beanType;

   //该属性就是Controller类中的带有@RequestMapping注解的方法
   private final Method method;

   private final Method bridgedMethod;

   private final MethodParameter[] parameters;

   @Nullable
   private HttpStatus responseStatus;

   @Nullable
   private String responseStatusReason;

   @Nullable
   private HandlerMethod resolvedFromHandlerMethod;
   
   
   //省略不重要的部分
}

处理器适配器

注册流程

分析源码入口:RequestMappingHandlerAdapter#afterPropertiesSet

//重点该方法
@Override
public void afterPropertiesSet() {
   // Do this first, it may add ResponseBody advice beans
   //初始化Controller类通知缓存
   initControllerAdviceCache();

   //初始化参数解析器
   if (this.argumentResolvers == null) {
      //点进去看看getDefaultArgumentResolvers
      List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers();
      this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
   }
   //初始化处理器Binder参数解析器
   if (this.initBinderArgumentResolvers == null) {
      List<HandlerMethodArgumentResolver> resolvers = getDefaultInitBinderArgumentResolvers();
      this.initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
   }
   //初始化处理器返回值解析器
   if (this.returnValueHandlers == null) {
      List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers();
      this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);
   }
}
  • 以上方法,分别注册了处理器增强类的相关操作(@ModelAttribute、@InitBinder、@ExceptionHandler)、参数解析器、initBinder参数解析器、返回值处理器

  • 这些注册的参数解析器和返回值处理器会在执行Handler方法时进行调用。

处理流程

分析源码入口:DispatcherServlet#doDispatcher方法

主要分为两个流程:

  • 根据Handler获取到对应的HandlerAdapter

  • 执行Handler对应的handle方法,也就是@Controller类中的带有@RequestMapping注解的方法,底层是通过反射来实现的,即Method.invoke(obj,args)

先来看第一个流程: HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

/**
 *
 * 重点
 * 通过找到的Handler处理器,去匹配合适的处理器适配器HandlerAdapter
 */
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
   if (this.handlerAdapters != null) {
      for (HandlerAdapter ha : this.handlerAdapters) {
         if (logger.isTraceEnabled()) {
            logger.trace("Testing handler adapter [" + ha + "]");
         }
         //通过适配器的适配功能,去适配处理器,如果适配成功,则直接返回处理器适配器
         if (ha.supports(handler)) {
            return ha;
         }
      }
   }
   throw new ServletException("No adapter for handler [" + handler +
         "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}

查看HnadlerAdapter接口的其中一个实现类HttpRequestHandlerAdapter中的supports方法如下:

public class HttpRequestHandlerAdapter implements HandlerAdapter {

   @Override
   public boolean supports(Object handler) {
      return (handler instanceof HttpRequestHandler);
   }
}

由以上可知,该处理器适配器是适配实现了HttpRequestHandler接口的Handler,第一个流程到此结束。

接下来查看第二个流程: mv = ha.handle(processedRequest, response, mappedHandler.getHandler())

接着调用AbstractHandlerMethdAdapter类中的handle方法

image.png

进入RequestMappingHandlerAdapter#handleInternal方法

image.png

进入invokeHandlerMethod方法

@Nullable
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
      HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

   ServletWebRequest webRequest = new ServletWebRequest(request, response);
   try {
      //获取数据绑定工厂,作用是为了获取WebDataBinder,WebDataBinder给参数进行类型转换
      WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
      ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);

      ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
      //设置参数解析器
      if (this.argumentResolvers != null) {
         invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
      }
      //设置返回值解析器
      if (this.returnValueHandlers != null) {
         invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
      }
      invocableMethod.setDataBinderFactory(binderFactory);
      invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);

      ModelAndViewContainer mavContainer = new ModelAndViewContainer();
      mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
      modelFactory.initModel(webRequest, mavContainer, invocableMethod);
      mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);

      AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
      asyncWebRequest.setTimeout(this.asyncRequestTimeout);

      WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
      asyncManager.setTaskExecutor(this.taskExecutor);
      asyncManager.setAsyncWebRequest(asyncWebRequest);
      asyncManager.registerCallableInterceptors(this.callableInterceptors);
      asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);

      if (asyncManager.hasConcurrentResult()) {
         Object result = asyncManager.getConcurrentResult();
         mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0];
         asyncManager.clearConcurrentResult();
         if (logger.isDebugEnabled()) {
            logger.debug("Found concurrent result value [" + result + "]");
         }
         invocableMethod = invocableMethod.wrapConcurrentResult(result);
      }

      //重点
      //调用HnadlerMethod
      invocableMethod.invokeAndHandle(webRequest, mavContainer);
      if (asyncManager.isConcurrentHandlingStarted()) {
         return null;
      }

      return getModelAndView(mavContainer, modelFactory, webRequest);
   }
   finally {
      webRequest.requestCompleted();
   }
}

接下来查看invocableMethod.invokeAndHandle(webRequest, mavContainer);

/**
 * 重点
 */
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
      Object... providedArgs) throws Exception {

   //重点流程1
   //执行参数解析流程,HnadlerMethod处理流程,并返回i结果
   Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
   setResponseStatus(webRequest);

   if (returnValue == null) {
      if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) {
         mavContainer.setRequestHandled(true);
         return;
      }
   }
   else if (StringUtils.hasText(getResponseStatusReason())) {
      mavContainer.setRequestHandled(true);
      return;
   }

   mavContainer.setRequestHandled(false);
   Assert.state(this.returnValueHandlers != null, "No return value handlers");
   try {
      //重点流程2
      //执行返回值解析流程,主要了解@ResponseBody注解修饰的返回值解析
      this.returnValueHandlers.handleReturnValue(
            returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
   }
   catch (Exception ex) {
      if (logger.isTraceEnabled()) {
         logger.trace(getReturnValueHandlingErrorMessage("Error handling return value", returnValue), ex);
      }
      throw ex;
   }
}

接下来查看invokeForRequest方法,如下:

@Nullable
public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
      Object... providedArgs) throws Exception {

   //获取方法参数值(这一步也是从request中将参数解析出来的过程)
   //重点看一下getMethodArgumentValues源码
   Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
   if (logger.isTraceEnabled()) {
      logger.trace("Invoking '" + ClassUtils.getQualifiedMethodName(getMethod(), getBeanType()) +
            "' with arguments " + Arrays.toString(args));
   }
   //重点
   //执行HandlerMethod方法,并获取返回值(也就是执行Controller类中的方法)
   Object returnValue = doInvoke(args);
   if (logger.isTraceEnabled()) {
      logger.trace("Method [" + ClassUtils.getQualifiedMethodName(getMethod(), getBeanType()) +
            "] returned [" + returnValue + "]");
   }
   return returnValue;
}

该方法一共有三个重点流程,如下:

  • 获取Controller类中的对应的方法的请求参数值Object[] args
  • 执行Controller类中的对应的方法,底层Method.invoke(obj,args)
  • 将返回值返回。

咱们这里重点查看第二步骤:执行Controller类中的对应的方法,底层Method.invoke(obj,args) ,于是查看Object returnValue = doInvoke(args);

image.png

参数绑定流程

分析入口:InvocableHandlerMethod#invokeForRequest方法

image.png

进入getMethodArgumentValues方法

private Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
      Object... providedArgs) throws Exception {

   //得到HandlerMethod中的参数集合
   MethodParameter[] parameters = getMethodParameters();
   //该数组中存放的数据,已经是经过类型转换之后的参数了
   Object[] args = new Object[parameters.length];
   //遍历每一个参数
   for (int i = 0; i < parameters.length; i++) {
      MethodParameter parameter = parameters[i];
      //初始化参数名称发现者(通过反射获取参数类型容易,但是获取参数名称需要特殊处理)
      parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
      //解决默认支持的参数
      args[i] = resolveProvidedArgument(parameter, providedArgs);
      if (args[i] != null) {
         continue;
      }
      //根据参数匹配参数解析器
      if (this.argumentResolvers.supportsParameter(parameter)) {
         try {
            //重点
            //执行参数解析(将request中将请求数据,绑定到方法参数中)
            args[i] = this.argumentResolvers.resolveArgument(
                  parameter, mavContainer, request, this.dataBinderFactory);
            continue;
         }
         catch (Exception ex) {
            if (logger.isDebugEnabled()) {
               logger.debug(getArgumentResolutionErrorMessage("Failed to resolve", i), ex);
            }
            throw ex;
         }
      }
      if (args[i] == null) {
         throw new IllegalStateException("Could not resolve method parameter at index " +
               parameter.getParameterIndex() + " in " + parameter.getExecutable().toGenericString() +
               ": " + getArgumentResolutionErrorMessage("No suitable resolver for", i));
      }
   }
   return args;
}

重点看看HandlerMethodArgumentResolverComposite#resolveArgument方法

public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
      NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {

   //找出可以解析该参数的参数解析器
   HandlerMethodArgumentResolver resolver = getArgumentResolver(parameter);
   if (resolver == null) {
      throw new IllegalArgumentException("Unsupported parameter type [" +
            parameter.getParameterType().getName() + "]. supportsParameter should be called first.");
   }
   //根据具体参数解析器的参数解析工作
   //重点看两个
   //1.AbstractNamedValueMethodArgumentResolver:用于解析简单类型参数
   //2.ModelAttributeMethodProcessor:用于解析pojo参数类型
   return resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory);
}

此处需要根据具体参数类型调用相应的解析器,

  • 其中简单类型调用的都是AbstractNamedValueMethodArgumentResolver类中的方法;

  • POJO类型调用的都是ModelAttributeMethodProcessor类中的方法。我们就以简单类型(对应AbstractNamedValueMethodArgumentResolver)为例给大家讲解一下具体的参数绑定过程

//用于解析简单类型的参数
public final Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
      NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {

   //NamedValueInfo对象封装了方法参数(方法名称,是否必须,默认值)三个信息,相当于@RequestParam注解中的三个属性
   NamedValueInfo namedValueInfo = getNamedValueInfo(parameter);
   MethodParameter nestedParameter = parameter.nestedIfOptional();

   //将方法参数名称处理一下
   Object resolvedName = resolveStringValue(namedValueInfo.name);
   if (resolvedName == null) {
      throw new IllegalArgumentException(
            "Specified name must not resolve to null: [" + namedValueInfo.name + "]");
   }

   //从request请求中解析出来指定的key(参数名称)的值,即request.getParameter("xxx");
   //此时从request中解析出来的参数值都是String类型的
   Object arg = resolveName(resolvedName.toString(), nestedParameter, webRequest);
   //空值处理
   if (arg == null) {
      //使用默认值设置参数值
      if (namedValueInfo.defaultValue != null) {
         arg = resolveStringValue(namedValueInfo.defaultValue);
      }
      else if (namedValueInfo.required && !nestedParameter.isOptional()) {
         handleMissingValue(namedValueInfo.name, nestedParameter, webRequest);
      }
      //处理空值情况
      arg = handleNullValue(namedValueInfo.name, arg, nestedParameter.getNestedParameterType());
   }
   else if ("".equals(arg) && namedValueInfo.defaultValue != null) {
      arg = resolveStringValue(namedValueInfo.defaultValue);
   }

   //重点
   //使用WebDataBinder进行数据类型转换
   //WebDataBinder会根据不同的参数,选择不同的PropertyEditor进行参数类型转换
   //而大多数的PropertyEditor都已经内置了,那么如果需要自定义添加PropertyEditor的话,需要使用@InitBinder注解的方法进行处理
   if (binderFactory != null) {
      //获取web数据绑定器,主要作用将request请求参数中的值,转换成指定类型的Controller方法中的参数类型
      WebDataBinder binder = binderFactory.createBinder(webRequest, null, namedValueInfo.name);
      try {
         //重点
         //使用web绑定器,将string类型的请求数据,转换成指定数据类型,并绑定到指定方法参数中
         //此处有两个arg变量,作为参数是string类型,作为返回值,已经变为了其他类型
         //parameter是Controller类中的方法的参数,即形参
         arg = binder.convertIfNecessary(arg, parameter.getParameterType(), parameter);
      }
      catch (ConversionNotSupportedException ex) {
         throw new MethodArgumentConversionNotSupportedException(arg, ex.getRequiredType(),
               namedValueInfo.name, parameter, ex.getCause());
      }
      catch (TypeMismatchException ex) {
         throw new MethodArgumentTypeMismatchException(arg, ex.getRequiredType(),
               namedValueInfo.name, parameter, ex.getCause());
      }
   }
   handleResolvedValue(arg, namedValueInfo.name, parameter, mavContainer, webRequest);
   return arg;
}

我们进入RequestParamMethodArgumentResolver#resolveName方法看看

image.png 至于参数绑定器的源码比较复杂,我们就不深入追踪了,我们只需要知道参数转换方式有两种处理方式:PropertyEditorConversionService,以及它们处理参数转换的区别就行了。下面的代码是在**TypeConverterDelegate**类中的

@Override
@Nullable
public <T> T convertIfNecessary(@Nullable Object value, @Nullable Class<T> requiredType,
      @Nullable MethodParameter methodParam) throws TypeMismatchException {

   //获取不同的类型转换器,对参数进行绑定
   //我们选择TypeConverterSupport转换器
   return getTypeConverter().convertIfNecessary(value, requiredType, methodParam);
}

接着查看TypeConverterSupport类中的convertIfNecessary方法

image.png

image.png

image.png

最终来到TypeConverterDelegate类中的convertIfNecessary方法,如下:

/**
 * 重点
 * 类型转换就看到该方法就行了,到头了,不要再往下挖了
 */
@SuppressWarnings("unchecked")
@Nullable
public <T> T convertIfNecessary(@Nullable String propertyName, @Nullable Object oldValue, @Nullable Object newValue,
      @Nullable Class<T> requiredType, @Nullable TypeDescriptor typeDescriptor) throws IllegalArgumentException {

   // Custom editor for this type?
   //获取自定义属性编辑器
   //属性编辑器的作用就是string类型转换成任意类型
   PropertyEditor editor = this.propertyEditorRegistry.findCustomEditor(requiredType, propertyName);

   ConversionFailedException conversionAttemptEx = null;

   // No custom editor but custom ConversionService specified?
   //获取自定义类型转换服务
   //Converter的作用是任意类型到任意类型的转换
   ConversionService conversionService = this.propertyEditorRegistry.getConversionService();
   if (editor == null && conversionService != null && newValue != null && typeDescriptor != null) {
      TypeDescriptor sourceTypeDesc = TypeDescriptor.forObject(newValue);
      if (conversionService.canConvert(sourceTypeDesc, typeDescriptor)) {
         try {
            //使用自定义的ConversionService,完成类型转换
            return (T) conversionService.convert(newValue, sourceTypeDesc, typeDescriptor);
         }
         catch (ConversionFailedException ex) {
            // fallback to default conversion logic below
            conversionAttemptEx = ex;
         }
      }
   }

   Object convertedValue = newValue;
   
   //省略不重要代码
}

返回值处理流程

分析入口:ServletInvocableHandlerMethod#invokeAndHandle方法

image.png

返回值由this.returnValueHandlers进行处理,这个成员变量的类型是HandlerMethodReturnValueHandlerComposite,它继承自HandlerMethodReturnValueHandler类,该类有两个方法:

image.png

我们进入HandlerMethodReturnValueHandlerComposite#handleReturnValue方法

image.png

至此返回值处理流程我们就分析完了

ResponseBody注解解析

如果返回值使用@ResponseBody注解,那么由它注解的返回值会使用 RequestResponseBodyMethodProcessor类进行返回值处理。

//处理@ResponseBody注解的返回值处理器
@Override
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
      ModelAndViewContainer mavContainer, NativeWebRequest webRequest)
      throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {

   mavContainer.setRequestHandled(true);
   ServletServerHttpRequest inputMessage = createInputMessage(webRequest);
   ServletServerHttpResponse outputMessage = createOutputMessage(webRequest);

   // Try even with null return value. ResponseBodyAdvice could get involved.
   //重点
   writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);
}

进入AbstractMessageConverterMethodProcessor#writeWithMessageConverters方法,这个方法的处理逻辑比较长,我们挑重点的代码进行阅读

image.png

image.png

继续深入AbstractGenericHttpMessageConverter#write方法

image.png

进入writeInternal方法

image.png

image.png