• SpringMVC核心流程分析(源码讲解)


    目录

       

     1 异步线程管理WebAsyncManager

     2 判断是否是一个文件上传请求

     3 获取符合条件的mappedHandler

      3.1 什么是handlerMappings

      3.2 mapping.getHandler(request)是干什么

     3.2.1 怎么返回不为空的handler

      3.2.2 为什么别的Mapping不满足

      3.2.3 返回HandlerExecutionChain    

     4 获取HandlerAdapter

        4.1什么是HandlerAdapter

        4.2List的初始化

        4.3获取合适的HandlerAdapter

     5 获取ModelAndView    

      5.1 获取方法参数

      5.2 处理返回数据

    6 开启异步线程管理

    7 小结


    关于SpringMVC的工作流程,大多数人想必都不太陌生,基本就是前端一个http链接,通过Servlet转发到后端指定的Controller层,找到指定的方法,执行便完了。
    那么其具体的细节到底是怎样的,我们通过源码来一步步的进行深究。

    1. protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
    2.         HttpServletRequest processedRequest = request;
    3.         HandlerExecutionChain mappedHandler = null;
    4.         boolean multipartRequestParsed = false;
    5.         //1设置异步线程管理
    6.         WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
    7.         try {
    8.             try {
    9.                 ModelAndView mv = null;
    10.                 Object dispatchException = null;
    11.                 try {
    12.                     //2判断是否是一个文件上传请求
    13.                     processedRequest = this.checkMultipart(request);
    14.                     multipartRequestParsed = processedRequest != request;
    15.                     //3获取符合条件的mappedHandler
    16.                     mappedHandler = this.getHandler(processedRequest);
    17.                     if (mappedHandler == null) {
    18.                         this.noHandlerFound(processedRequest, response);
    19.                         return;
    20.                     }
    21.                     //4获取HandlerAdapter
    22.                     HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());
    23.                     String method = request.getMethod();
    24.                     boolean isGet = "GET".equals(method);
    25.                     if (isGet || "HEAD".equals(method)) {
    26.                         long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
    27.                         if ((new ServletWebRequest(request, response)).checkNotModified(lastModified) && isGet) {
    28.                             return;
    29.                         }
    30.                     }
    31.                     if (!mappedHandler.applyPreHandle(processedRequest, response)) {
    32.                         return;
    33.                     }
    34.                     //5获取ModelAndView
    35.                     mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
    36.                     //6开启异步线程管理
    37.                     if (asyncManager.isConcurrentHandlingStarted()) {
    38.                         return;
    39.                     }
    40.                     this.applyDefaultViewName(processedRequest, mv);
    41.                     mappedHandler.applyPostHandle(processedRequest, response, mv);
    42.                 } catch (Exception var20) {
    43.                     dispatchException = var20;
    44.                 } catch (Throwable var21) {
    45.                     dispatchException = new NestedServletException("Handler dispatch failed", var21);
    46.                 }
    47.                 this.processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException);
    48.             } catch (Exception var22) {
    49.                 this.triggerAfterCompletion(processedRequest, response, mappedHandler, var22);
    50.             } catch (Throwable var23) {
    51.                 this.triggerAfterCompletion(processedRequest, response, mappedHandler, new NestedServletException("Handler processing failed", var23));
    52.             }
    53.         } finally {
    54.             if (asyncManager.isConcurrentHandlingStarted()) {
    55.                 if (mappedHandler != null) {
    56.                     mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
    57.                 }
    58.             } else if (multipartRequestParsed) {
    59.                 this.cleanupMultipart(processedRequest);
    60.             }
    61.         }
    62.     }

       

     1 异步线程管理WebAsyncManager


            在看MVC的异步线程管理之前,我们可以粗略的看一看,等了解后面的流程之后再回头看,就会比较清晰。
            初略看来就是通过工具类获取了一个WebAsyncManager,然后在执行完ha.handle之后,这个方法就直接返回了。为什么会这样呢?
            我们可以看一下ha.handle执行的目的。    


     2 判断是否是一个文件上传请求


            通过this.checkMultipart(request),判断这个servlet请求是否是一个文件上传请求,如果是,需要在后续调用this.cleanupMultipart(processedRequest)
            执行清除文件上传的部分属性。
        

     3 获取符合条件的mappedHandler


            通过this.getHandler(processedRequest)获取符合条件的mappedHandler    

    1. protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    2.         if (this.handlerMappings != null) {
    3.             Iterator var2 = this.handlerMappings.iterator();
    4.             while(var2.hasNext()) {
    5.                 HandlerMapping mapping = (HandlerMapping)var2.next();
    6.                 HandlerExecutionChain handler = mapping.getHandler(request);
    7.                 if (handler != null) {
    8.                     return handler;
    9.                 }
    10.             }
    11.         }
    12.         return null;
    13.     }

            通过代码可知,就是通过当前类的handlerMappings迭代循环,根据request参数,找到一个不为null的handler返回即可。那么有两步工作需要搞清楚,
            第一步什么是handlerMappings,第二步mapping.getHandler(request)是什么
            想要获取mappedHandler,先要了解handlerMappings
        


      3.1 什么是handlerMappings


        handlerMappings其实就是接口HandlerMapping实现类的List形式。        

    1. public interface HandlerMapping {
    2.         String BEST_MATCHING_HANDLER_ATTRIBUTE = HandlerMapping.class.getName() + ".bestMatchingHandler";
    3.         String LOOKUP_PATH = HandlerMapping.class.getName() + ".lookupPath";
    4.         String PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE = HandlerMapping.class.getName() + ".pathWithinHandlerMapping";
    5.         String BEST_MATCHING_PATTERN_ATTRIBUTE = HandlerMapping.class.getName() + ".bestMatchingPattern";
    6.         String INTROSPECT_TYPE_LEVEL_MAPPING = HandlerMapping.class.getName() + ".introspectTypeLevelMapping";
    7.         String URI_TEMPLATE_VARIABLES_ATTRIBUTE = HandlerMapping.class.getName() + ".uriTemplateVariables";
    8.         String MATRIX_VARIABLES_ATTRIBUTE = HandlerMapping.class.getName() + ".matrixVariables";
    9.         String PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE = HandlerMapping.class.getName() + ".producibleMediaTypes";
    10.         @Nullable
    11.         HandlerExecutionChain getHandler(HttpServletRequest var1) throws Exception;
    12.     }

        可以看到,其核心方法便是getHandler。
        那么handlerMappings的值是如何构造的呢?  
        从DispatcherServlet类中,我们可以看到ioc容器启动的方法:


        protected void onRefresh(ApplicationContext context) {
            this.initStrategies(context);
        }

        可以看到在容器启动时,会加载一系列的组件,其中就有handlerMappings。    

    1. protected void initStrategies(ApplicationContext context) {
    2.         this.initMultipartResolver(context);
    3.         this.initLocaleResolver(context);
    4.         this.initThemeResolver(context);
    5.         this.initHandlerMappings(context);
    6.         this.initHandlerAdapters(context);
    7.         this.initHandlerExceptionResolvers(context);
    8.         this.initRequestToViewNameTranslator(context);
    9.         this.initViewResolvers(context);
    10.         this.initFlashMapManager(context);
    11.     }

      其具体方法如下:    

    1. private void initHandlerMappings(ApplicationContext context) {
    2.         this.handlerMappings = null;
    3.         if (this.detectAllHandlerMappings) {
    4.             Map matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
    5.             if (!matchingBeans.isEmpty()) {
    6.                 this.handlerMappings = new ArrayList(matchingBeans.values());
    7.                 AnnotationAwareOrderComparator.sort(this.handlerMappings);
    8.             }
    9.         } else {
    10.             try {
    11.                 HandlerMapping hm = (HandlerMapping)context.getBean("handlerMapping", HandlerMapping.class);
    12.                 this.handlerMappings = Collections.singletonList(hm);
    13.             } catch (NoSuchBeanDefinitionException var3) {
    14.             }
    15.         }
    16.         if (this.handlerMappings == null) {
    17.             this.handlerMappings = this.getDefaultStrategies(context, HandlerMapping.class);
    18.             if (this.logger.isTraceEnabled()) {
    19.                 this.logger.trace("No HandlerMappings declared for servlet '" + this.getServletName() + "': using default strategies from DispatcherServlet.properties");
    20.             }
    21.         }
    22.     }

            由于this.detectAllHandlerMappings默认为true,所以上面构造handlerMappings的核心方法便是:
        Map matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
            进入beansOfTypeIncludingAncestors,handlerMappings的构造实现:  

    1.  public static Map beansOfTypeIncludingAncestors(ListableBeanFactory lbf, Class type, boolean includeNonSingletons, boolean allowEagerInit) throws BeansException {
    2.         Assert.notNull(lbf, "ListableBeanFactory must not be null");
    3.         Map result = new LinkedHashMap(4);
    4.         result.putAll(lbf.getBeansOfType(type, includeNonSingletons, allowEagerInit));
    5.         if (lbf instanceof HierarchicalBeanFactory) {
    6.             HierarchicalBeanFactory hbf = (HierarchicalBeanFactory)lbf;
    7.             if (hbf.getParentBeanFactory() instanceof ListableBeanFactory) {
    8.                 Map parentResult = beansOfTypeIncludingAncestors((ListableBeanFactory)hbf.getParentBeanFactory(), type, includeNonSingletons, allowEagerInit);
    9.                 parentResult.forEach((beanName, beanInstance) -> {
    10.                     if (!result.containsKey(beanName) && !hbf.containsLocalBean(beanName)) {
    11.                         result.put(beanName, beanInstance);
    12.                     }
    13.                 });
    14.             }
    15.         }
    16.         return result;
    17.     }


        总结上面的代码便是,通过ioc的容器中的ListableBeanFactory,根据一系列的条件:HandlerMapping.class、includeNonSingletons、allowEagerInit获取满足条件的HandlerMapping接口的实现类:
        {requestMappingHandlerMapping=org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping@1077a7, welcomePageHandlerMapping=org.springframework.boot.autoconfigure.web.servlet.WelcomePageHandlerMapping@3c3d2a80, beanNameHandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping@685280dd,
        routerFunctionMapping=org.springframework.web.servlet.function.support.RouterFunctionMapping@879f852,
        resourceHandlerMapping=org.springframework.web.servlet.handler.SimpleUrlHandlerMapping@792bf78a}

            可以看到,返回的都是HandlerMapping的实现类,但不是其实现类的全部。在这里我们需要记住RequestMappingHandlerMapping这个类,也就是我们后续会用到的。
           


      3.2 mapping.getHandler(request)是干什么


            说起mapping.getHandler(request)就不得不提起其实现方法,我们通过HandlerMapping接口可以看到,其有一个可以不实现的方法getHandler:
            @Nullable
            HandlerExecutionChain getHandler(HttpServletRequest var1) throws Exception;
            通过HandlerMapping的实现类可以看出,仅有一个AbstractHandlerMapping实现了getHandler方法,也就是:    

    1. @Nullable
    2.     public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    3.         Object handler = this.getHandlerInternal(request);
    4.         if (handler == null) {
    5.             handler = this.getDefaultHandler();
    6.         }
    7.         if (handler == null) {
    8.             return null;
    9.         } else {
    10.             if (handler instanceof String) {
    11.                 String handlerName = (String)handler;
    12.                 handler = this.obtainApplicationContext().getBean(handlerName);
    13.             }
    14.             HandlerExecutionChain executionChain = this.getHandlerExecutionChain(handler, request);
    15.             if (this.logger.isTraceEnabled()) {
    16.                 this.logger.trace("Mapped to " + handler);
    17.             } else if (this.logger.isDebugEnabled() && !request.getDispatcherType().equals(DispatcherType.ASYNC)) {
    18.                 this.logger.debug("Mapped to " + executionChain.getHandler());
    19.             }
    20.             if (this.hasCorsConfigurationSource(handler) || CorsUtils.isPreFlightRequest(request)) {
    21.                 CorsConfiguration config = this.corsConfigurationSource != null ? this.corsConfigurationSource.getCorsConfiguration(request) : null;
    22.                 CorsConfiguration handlerConfig = this.getCorsConfiguration(handler, request);
    23.                 config = config != null ? config.combine(handlerConfig) : handlerConfig;
    24.                 executionChain = this.getCorsHandlerExecutionChain(request, executionChain, config);
    25.             }
    26.             return executionChain;
    27.         }
    28.     }

           通过getHandler的前6行代码和3.1中的代码相结合,我们可以看出,只有返回了不为空的handler,mapping.getHandler(request)这个方法才会返回有效值。
        


     3.2.1 怎么返回不为空的handler


        那么怎么返回不为空的handler呢?看RequestMappingHandlerMapping。
        Object handler = this.getHandlerInternal(request);
        通过RequestMappingHandlerMapping的getHandlerInternal方法,来看是如何取handler的:    

    1. protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
    2.         request.removeAttribute(PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE);
    3.         HandlerMethod var2;
    4.         try {
    5.             var2 = super.getHandlerInternal(request);
    6.         } finally {
    7.             ProducesRequestCondition.clearMediaTypesAttribute(request);
    8.         }
    9.         return var2;
    10.     }

            可以看到是通过父类AbstractHandlerMapping的getHandlerInternal方法来获取的:    

    1. protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
    2.         //计算出请求路径
    3.         String lookupPath = this.getUrlPathHelper().getLookupPathForRequest(request);
    4.         request.setAttribute(LOOKUP_PATH, lookupPath);
    5.         //设置读锁
    6.         this.mappingRegistry.acquireReadLock();
    7.         HandlerMethod var4;
    8.         try {
    9.             //根据request参数,找到对应controller层方法
    10.             HandlerMethod handlerMethod = this.lookupHandlerMethod(lookupPath, request);
    11.             var4 = handlerMethod != null ? handlerMethod.createWithResolvedBean() : null;
    12.         } finally {
    13.             //释放锁
    14.             this.mappingRegistry.releaseReadLock();
    15.         }
    16.         return var4;
    17.     }


           可以看到,getHandlerInternal这个方法就是根据request请求的信息,来找到后台对应controller层的方法。
           举个例子,前端请求localhost:8080/test,lookupPath便是解析出/test,然后根据解析出的参数去找对应方法HandlerMethod。
            而HandlerMethod这个类中就包含了执行方法的一系列属性,包括beanName,方法注解,方法名称,方法参数等一系列属性,取到之后方便后续操作。
            去哪里找呢?在this.lookupHandlerMethod(lookupPath, request)中。    

    1. protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
    2.         List.Match> matches = new ArrayList();
    3.         //根据路径去集合中查找到所有满足条件的路径集合
    4.         List directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
    5.         if (directPathMatches != null) {
    6.         //根据路径集合去找可能满足条件的方法matches
    7.             this.addMatchingMappings(directPathMatches, matches, request);
    8.         }
    9.         if (matches.isEmpty()) {
    10.             this.addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request);
    11.         }
    12.         if (!matches.isEmpty()) {
    13.             AbstractHandlerMethodMapping.Match bestMatch = (AbstractHandlerMethodMapping.Match)matches.get(0);
    14.             if (matches.size() > 1) {
    15.                 Comparator.Match> comparator = new AbstractHandlerMethodMapping.MatchComparator(this.getMappingComparator(request));
    16.                 matches.sort(comparator);
    17.                 bestMatch = (AbstractHandlerMethodMapping.Match)matches.get(0);
    18.                 if (this.logger.isTraceEnabled()) {
    19.                     this.logger.trace(matches.size() + " matching mappings: " + matches);
    20.                 }
    21.                 if (CorsUtils.isPreFlightRequest(request)) {
    22.                     return PREFLIGHT_AMBIGUOUS_MATCH;
    23.                 }
    24.                 AbstractHandlerMethodMapping.Match secondBestMatch = (AbstractHandlerMethodMapping.Match)matches.get(1);
    25.                 if (comparator.compare(bestMatch, secondBestMatch) == 0) {
    26.                     Method m1 = bestMatch.handlerMethod.getMethod();
    27.                     Method m2 = secondBestMatch.handlerMethod.getMethod();
    28.                     String uri = request.getRequestURI();
    29.                     throw new IllegalStateException("Ambiguous handler methods mapped for '" + uri + "': {" + m1 + ", " + m2 + "}");
    30.                 }
    31.             }
    32.             request.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, bestMatch.handlerMethod);
    33.             //找到最合适的方法返回
    34.             this.handleMatch(bestMatch.mapping, lookupPath, request);
    35.             return bestMatch.handlerMethod;
    36.         } else {
    37.             return this.handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
    38.         }
    39.     }

            在lookupHandlerMethod中,可以详细的看到是如何通过lookupPath的参数来寻找对应的controller层方法的。
            其大致意思就是去一个集合中,找到满足lookupPath参数的所有方法,然后再从所有方法中,通过比较,找一个最合适的controller层方法返回。
            之后再通过handlerMethod.createWithResolvedBean(),返回真正的执行方法:    

    1. public HandlerMethod createWithResolvedBean() {
    2.         //controller层的bean名称
    3.         Object handler = this.bean;
    4.         if (this.bean instanceof String) {
    5.             Assert.state(this.beanFactory != null, "Cannot resolve bean name without BeanFactory");
    6.             //获取beanName
    7.             String beanName = (String)this.bean;
    8.             //通过beanName,从ioc容器获取真正的bean
    9.             handler = this.beanFactory.getBean(beanName);
    10.         }
    11.         //构造HandlerMethod
    12.         return new HandlerMethod(this, handler);
    13.     }

            通过createWithResolvedBean,我们又可以反推出,上面的lookupHandlerMethod中返回的HandlerMethod,其实更多的返回的是一种类似于beanDefination的角色,
             存储了一些bean和其中指定方法的定义信息,而不是ioc容器中,已经实例化的bean。    
        


      3.2.2 为什么别的Mapping不满足


        别的怎么会返回空呢?举个例子,BeanNameUrlHandlerMapping的实现:  

    1.  @Nullable
    2.     protected Object getHandlerInternal(HttpServletRequest request) throws Exception {
    3.         String lookupPath = this.getUrlPathHelper().getLookupPathForRequest(request);
    4.         request.setAttribute(LOOKUP_PATH, lookupPath);
    5.         Object handler = this.lookupHandler(lookupPath, request);
    6.         if (handler == null) {
    7.             Object rawHandler = null;
    8.             if ("/".equals(lookupPath)) {
    9.                 rawHandler = this.getRootHandler();
    10.             }
    11.             if (rawHandler == null) {
    12.                 rawHandler = this.getDefaultHandler();
    13.             }
    14.             if (rawHandler != null) {
    15.                 if (rawHandler instanceof String) {
    16.                     String handlerName = (String)rawHandler;
    17.                     rawHandler = this.obtainApplicationContext().getBean(handlerName);
    18.                 }
    19.                 this.validateHandler(rawHandler, request);
    20.                 handler = this.buildPathExposingHandler(rawHandler, lookupPath, lookupPath, (Map)null);
    21.             }
    22.         }
    23.         return handler;
    24.     }

        可以看到关键方法便是Object handler = this.lookupHandler(lookupPath, request): 

    1.    protected Object lookupHandler(String urlPath, HttpServletRequest request) throws Exception {
    2.         Object handler = this.handlerMap.get(urlPath);
    3.         if (handler != null) {
    4.             if (handler instanceof String) {
    5.                 String handlerName = (String)handler;
    6.                 handler = this.obtainApplicationContext().getBean(handlerName);
    7.             }

           原因便是handlerMap中没有根据urlPath,找到对应的handler,这是由于BeanNameUrlHandlerMapping的作用主要是加载classpatch下面一些默认的url路径。
            它的职责定位并不是用来做controller层的转发。    


      3.2.3 返回HandlerExecutionChain
        

           在找到handler后呢?根据3.2中的代码,还有一步重要工作,那就是根据handler我们可以构造一个HandlerExecutionChain,翻译过来就是方法的执行链。
            其作用就是为了对springMVC的请求做一些额外的扩展,比如在进入controller层方法之前,先执行一些拦截器,例如CacheInteceptor,MyBatisInteceptor等等:   

    1.  protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
    2.         HandlerExecutionChain chain = handler instanceof HandlerExecutionChain ? (HandlerExecutionChain)handler : new HandlerExecutionChain(handler);
    3.         String lookupPath = this.urlPathHelper.getLookupPathForRequest(request, LOOKUP_PATH);
    4.         Iterator var5 = this.adaptedInterceptors.iterator();
    5.         while(var5.hasNext()) {
    6.             HandlerInterceptor interceptor = (HandlerInterceptor)var5.next();
    7.             if (interceptor instanceof MappedInterceptor) {
    8.                 MappedInterceptor mappedInterceptor = (MappedInterceptor)interceptor;
    9.                 if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
    10.                     chain.addInterceptor(mappedInterceptor.getInterceptor());
    11.                 }
    12.             } else {
    13.                 chain.addInterceptor(interceptor);
    14.             }
    15.         }
    16.         return chain;
    17.     }

            可以看到,this.adaptedInterceptors就是在容器初始化的时候会加载一些系统自带,和我们自定义的一些列interceptor,然后再把他们加入到HandlerExecutionChain中。
            其原理便在HandlerExecutionChain这个类的定义中:    

    1. public class HandlerExecutionChain {
    2.     private static final Log logger = LogFactory.getLog(HandlerExecutionChain.class);
    3.     private final Object handler;
    4.     @Nullable
    5.     private HandlerInterceptor[] interceptors;
    6.     @Nullable
    7.     private List interceptorList;
    8.     private int interceptorIndex;
    9.     public HandlerExecutionChain(Object handler) {
    10.         this(handler, (HandlerInterceptor[])null);
    11.     }
    12.     ......

           可以看到,HandlerExecutionChain其实就是handler和拦截器的一个组合类。    
           这样就走完了mappedHandler = this.getHandler(processedRequest)中的执行流程,返回了一个带有interceptor集合的HandlerExecutionChain,以后执行方法的时候,就可以其中的interceptor集合先执行一次。
           这样就能够对SpringMVC项目做一定的定制。
        


     4 获取HandlerAdapter


        在获取到mappedHandler之后呢,下一步便是获取HandlerAdapter:  

    1.  protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
    2.         if (this.handlerAdapters != null) {
    3.             Iterator var2 = this.handlerAdapters.iterator();
    4.             while(var2.hasNext()) {
    5.                 HandlerAdapter adapter = (HandlerAdapter)var2.next();
    6.                 if (adapter.supports(handler)) {
    7.                     return adapter;
    8.                 }
    9.             }
    10.         }
    11.         throw new ServletException("No adapter for handler [" + handler + "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
    12.     }

       


        4.1什么是HandlerAdapter


         和第三步处理类似,我们先看下HandlerAdapter的类信息:   

    1.      public interface HandlerAdapter {
    2.         boolean supports(Object var1);
    3.         @Nullable
    4.         ModelAndView handle(HttpServletRequest var1, HttpServletResponse var2, Object var3) throws Exception;
    5.         long getLastModified(HttpServletRequest var1, Object var2);
    6.     }

            比较简单,可以看到,其核心方法应该是执行handle以后返回一个ModelAndView,而我们这一步还没到handle,仅仅是获取到合适的HandlerAdapter实现类就行了。
        


        4.2List的初始化


            和第三步类似,在同一个类中,handlerAdapters也是通过类似的方式初始化,代码就不贴了,得到的实现类如下:  

     {requestMappingHandlerAdapter=org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter@3edc999f, handlerFunctionAdapter=org.springframework.web.servlet.function.support.HandlerFunctionAdapter@670481b2, httpRequestHandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter@1e82b631, simpleControllerHandlerAdapter=org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter@42c2a1da}

           通过第四步的adapter.supports(handler)代码可以看到,基本就是满足某个条件以后返回其中之一的实现类。
        


        4.3获取合适的HandlerAdapter


            由于第一个RequestMappingHandlerAdapter的父类AbstractHandlerMethodAdapter,直接就满足了supports方法,所以我们直接就返回了RequestMappingHandlerAdapter    

    1. public abstract class AbstractHandlerMethodAdapter extends WebContentGenerator implements HandlerAdapter, Ordered {
    2.     private int order = 2147483647;
    3.     public AbstractHandlerMethodAdapter() {
    4.         super(false);
    5.     }
    6.     public void setOrder(int order) {
    7.         this.order = order;
    8.     }
    9.     public int getOrder() {
    10.         return this.order;
    11.     }
    12.     public final boolean supports(Object handler) {
    13.         return handler instanceof HandlerMethod && this.supportsInternal((HandlerMethod)handler);
    14.     }
    15.      ......
    16.       protected boolean supportsInternal(HandlerMethod handlerMethod) {
    17.         return true;
    18.     }

           其实我们可以看到,最后的一个适配器SimpleControllerHandlerAdapter应该也是满足supports方法的,但是它的优先级在后面,所以没有选中。
        


     5 获取ModelAndView
        

          在第四步我们提到了,在获取到合适的适配器以后,我们会执行handle方法,也就是实际的controller层的指定方法,来获取指定的视图和数据。
        但是在执行handle之前和之后,会分别执行2个方法:mappedHandler.applyPreHandle(processedRequest, response)和mappedHandler.applyPostHandle(processedRequest, response, mv)。
        其实就是取到第三步中返回的HandlerExecutionChain中的interceptors拦截器,分别执行其pre和post方法,来做一些自定义开发。和bean实例化过程中的前置处理器和后置处理器有点类似。
           由于第四步中,我们取到的适配器是RequestMappingHandlerAdapter,所以handle的执行便来到了handleInternal中。
           由于后面的代码跳跃性比较多,在前面先说一下后面大体的执行逻辑,后面的执行逻辑和前面拦截器的pre和post方法方法有点类似,最重要的三个作用便是:
           第一步解析参数:Object[] args = this.getMethodArgumentValues(request, mavContainer, providedArgs)。
           第二步利用cglib代理真正执行方法:this.doInvoke(args)。
           第三步处理返回值:this.returnValueHandlers.handleReturnValue(returnValue, this.getReturnValueType(returnValue), mavContainer, webRequest)。
           其中的第一步和第三步,SpringMVC都提供了一系列的方法可以使用,还可以通过自定义的方式进行增强。
           在这里对返回值进行处理的好处是可以直接操作返回对象,而如果等到了handle执行完成之后,打算通过post来处理,会麻烦许多,因为到那个时候数据已经进respond变成了字节流,还需要转换一次。
           现在我们开始执行handleInternal:    

    1. protected ModelAndView handleInternal(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
    2.         this.checkRequest(request);
    3.         ModelAndView mav;
    4.         if (this.synchronizeOnSession) {
    5.             HttpSession session = request.getSession(false);
    6.             if (session != null) {
    7.                 Object mutex = WebUtils.getSessionMutex(session);
    8.                 synchronized(mutex) {
    9.                     mav = this.invokeHandlerMethod(request, response, handlerMethod);
    10.                 }
    11.             } else {
    12.                 mav = this.invokeHandlerMethod(request, response, handlerMethod);
    13.             }
    14.         } else {
    15.             mav = this.invokeHandlerMethod(request, response, handlerMethod);
    16.         }
    17.         if (!response.containsHeader("Cache-Control")) {
    18.             if (this.getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
    19.                 this.applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
    20.             } else {
    21.                 this.prepareResponse(response);
    22.             }
    23.         }
    24.         return mav;
    25.     }

        可以看到主要就是为了执行this.invokeHandlerMethod:    

    1. protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
    2.         ServletWebRequest webRequest = new ServletWebRequest(request, response);
    3.         ModelAndView var15;
    4.         try {
    5.             WebDataBinderFactory binderFactory = this.getDataBinderFactory(handlerMethod);
    6.             ModelFactory modelFactory = this.getModelFactory(handlerMethod, binderFactory);
    7.             ServletInvocableHandlerMethod invocableMethod = this.createInvocableHandlerMethod(handlerMethod);
    8.             if (this.argumentResolvers != null) {
    9.                 invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
    10.             }
    11.             if (this.returnValueHandlers != null) {
    12.                 invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
    13.             }
    14.             invocableMethod.setDataBinderFactory(binderFactory);
    15.             invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
    16.             ModelAndViewContainer mavContainer = new ModelAndViewContainer();
    17.             mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
    18.             modelFactory.initModel(webRequest, mavContainer, invocableMethod);
    19.             mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);
    20.             AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
    21.             asyncWebRequest.setTimeout(this.asyncRequestTimeout);
    22.             WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
    23.             asyncManager.setTaskExecutor(this.taskExecutor);
    24.             asyncManager.setAsyncWebRequest(asyncWebRequest);
    25.             asyncManager.registerCallableInterceptors(this.callableInterceptors);
    26.             asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);
    27.             Object result;
    28.             if (asyncManager.hasConcurrentResult()) {
    29.                 result = asyncManager.getConcurrentResult();
    30.                 mavContainer = (ModelAndViewContainer)asyncManager.getConcurrentResultContext()[0];
    31.                 asyncManager.clearConcurrentResult();
    32.                 LogFormatUtils.traceDebug(this.logger, (traceOn) -> {
    33.                     String formatted = LogFormatUtils.formatValue(result, !traceOn);
    34.                     return "Resume with async result [" + formatted + "]";
    35.                 });
    36.                 invocableMethod = invocableMethod.wrapConcurrentResult(result);
    37.             }
    38.             invocableMethod.invokeAndHandle(webRequest, mavContainer, new Object[0]);
    39.             if (asyncManager.isConcurrentHandlingStarted()) {
    40.                 result = null;
    41.                 return (ModelAndView)result;
    42.             }
    43.             var15 = this.getModelAndView(mavContainer, modelFactory, webRequest);
    44.         } finally {
    45.             webRequest.requestCompleted();
    46.         }
    47.         return var15;
    48.     }

        主要就是为了执行invocableMethod.invokeAndHandle(webRequest, mavContainer, new Object[0]):   

    1.  public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
    2.         //第一步和第二步集成方法
    3.         Object returnValue = this.invokeForRequest(webRequest, mavContainer, providedArgs);
    4.         this.setResponseStatus(webRequest);
    5.         if (returnValue == null) {
    6.             if (this.isRequestNotModified(webRequest) || this.getResponseStatus() != null || mavContainer.isRequestHandled()) {
    7.                 this.disableContentCachingIfNecessary(webRequest);
    8.                 mavContainer.setRequestHandled(true);
    9.                 return;
    10.             }
    11.         } else if (StringUtils.hasText(this.getResponseStatusReason())) {
    12.             mavContainer.setRequestHandled(true);
    13.             return;
    14.         }
    15.         mavContainer.setRequestHandled(false);
    16.         Assert.state(this.returnValueHandlers != null, "No return value handlers");
    17.         try {
    18.             //第三步处理返回数据
    19.             this.returnValueHandlers.handleReturnValue(returnValue, this.getReturnValueType(returnValue), mavContainer, webRequest);
    20.         } catch (Exception var6) {
    21.             if (this.logger.isTraceEnabled()) {
    22.                 this.logger.trace(this.formatErrorForReturnValue(returnValue), var6);
    23.             }
    24.             throw var6;
    25.         }
    26.     }
    1.  @Nullable
    2.     public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
    3.         //第一步,获取方法参数
    4.         Object[] args = this.getMethodArgumentValues(request, mavContainer, providedArgs);
    5.         if (this.logger.isTraceEnabled()) {
    6.             this.logger.trace("Arguments: " + Arrays.toString(args));
    7.         }
    8.         //第二步,执行方法
    9.         return this.doInvoke(args);
    10.     }

         我们的重点在第一步和第三步。


      5.1 获取方法参数

        

    1. protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
    2.         MethodParameter[] parameters = this.getMethodParameters();
    3.         if (ObjectUtils.isEmpty(parameters)) {
    4.             return EMPTY_ARGS;
    5.         } else {
    6.             Object[] args = new Object[parameters.length];
    7.             for(int i = 0; i < parameters.length; ++i) {
    8.                 MethodParameter parameter = parameters[i];
    9.                 parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
    10.                 args[i] = findProvidedArgument(parameter, providedArgs);
    11.                 if (args[i] == null) {
    12.                     if (!this.resolvers.supportsParameter(parameter)) {
    13.                         throw new IllegalStateException(formatArgumentError(parameter, "No suitable resolver"));
    14.                     }
    15.                     try {
    16.                         //解析每一个参数
    17.                         args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
    18.                     } catch (Exception var10) {
    19.                         if (this.logger.isDebugEnabled()) {
    20.                             String exMsg = var10.getMessage();
    21.                             if (exMsg != null && !exMsg.contains(parameter.getExecutable().toGenericString())) {
    22.                                 this.logger.debug(formatArgumentError(parameter, exMsg));
    23.                             }
    24.                         }
    25.                         throw var10;
    26.                     }
    27.                 }
    28.             }
    29.             return args;
    30.         }
    31.     }

            解析每一个参数,args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory): 

    1.    @Nullable
    2.     public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
    3.         HandlerMethodArgumentResolver resolver = this.getArgumentResolver(parameter);
    4.         if (resolver == null) {
    5.             throw new IllegalArgumentException("Unsupported parameter type [" + parameter.getParameterType().getName() + "]. supportsParameter should be called first.");
    6.         } else {
    7.             return resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory);
    8.         }
    9.     }

            重点便在HandlerMethodArgumentResolver这个类中,它有多达几十个实现类,可以来对参数进行解析,包括我们熟悉的@RequestParam注解参数,Pageable,@PathVariable,@ResponseBody等等,都可以进行解析:

    1.     public interface HandlerMethodArgumentResolver {
    2.         boolean supportsParameter(MethodParameter var1);
    3.         @Nullable
    4.         Object resolveArgument(MethodParameter var1, @Nullable ModelAndViewContainer var2, NativeWebRequest var3, @Nullable WebDataBinderFactory var4) throws Exception;
    5.     }

            可以看到,其实现方法定义和适配器类似,一个方法负责判断该选哪个参数选择器,另外一个方法负责具体的参数解析。
            举一个简单的实例:    

    1. public class PathVariableMapMethodArgumentResolver implements HandlerMethodArgumentResolver {
    2.         public PathVariableMapMethodArgumentResolver() {
    3.         }
    4.         public boolean supportsParameter(MethodParameter parameter) {
    5.             PathVariable ann = (PathVariable)parameter.getParameterAnnotation(PathVariable.class);
    6.             return ann != null && Map.class.isAssignableFrom(parameter.getParameterType()) && !StringUtils.hasText(ann.value());
    7.         }
    8.         public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
    9.             Map uriTemplateVars = (Map)webRequest.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, 0);
    10.             return !CollectionUtils.isEmpty(uriTemplateVars) ? new LinkedHashMap(uriTemplateVars) : Collections.emptyMap();
    11.         }
    12.     }


      5.2 处理返回数据


        通过this.returnValueHandlers.handleReturnValue(returnValue, this.getReturnValueType(returnValue), mavContainer, webRequest),我们可以看到如何处理返回数据:   

    1.  public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
    2.         HandlerMethodReturnValueHandler handler = this.selectHandler(returnValue, returnType);
    3.         if (handler == null) {
    4.             throw new IllegalArgumentException("Unknown return value type: " + returnType.getParameterType().getName());
    5.         } else {
    6.             handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
    7.         }
    8.     }

        和参数解析类似,重点在于HandlerMethodReturnValueHandler这个接口:  

    1.  public interface HandlerMethodReturnValueHandler {
    2.         boolean supportsReturnType(MethodParameter var1);
    3.         void handleReturnValue(@Nullable Object var1, MethodParameter var2, ModelAndViewContainer var3, NativeWebRequest var4) throws Exception;
    4.     }

        原理都一样,不再赘述,举个简单例子,我们常用的@RequestBody注解是如何解析返回数据的:   

    1.  public class RequestResponseBodyMethodProcessor extends AbstractMessageConverterMethodProcessor {
    2.     public RequestResponseBodyMethodProcessor(List> converters) {
    3.         super(converters);
    4.     }
    5.     public RequestResponseBodyMethodProcessor(List> converters, @Nullable ContentNegotiationManager manager) {
    6.         super(converters, manager);
    7.     }
    8.     public RequestResponseBodyMethodProcessor(List> converters, @Nullable List requestResponseBodyAdvice) {
    9.         super(converters, (ContentNegotiationManager)null, requestResponseBodyAdvice);
    10.     }
    11.     public RequestResponseBodyMethodProcessor(List> converters, @Nullable ContentNegotiationManager manager, @Nullable List requestResponseBodyAdvice) {
    12.         super(converters, manager, requestResponseBodyAdvice);
    13.     }
    14.     public boolean supportsParameter(MethodParameter parameter) {
    15.         return parameter.hasParameterAnnotation(RequestBody.class);
    16.     }
    17.     public boolean supportsReturnType(MethodParameter returnType) {
    18.         return AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), ResponseBody.class) || returnType.hasMethodAnnotation(ResponseBody.class);
    19.     }
    20.     public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
    21.         parameter = parameter.nestedIfOptional();
    22.         Object arg = this.readWithMessageConverters(webRequest, parameter, parameter.getNestedGenericParameterType());
    23.         String name = Conventions.getVariableNameForParameter(parameter);
    24.         if (binderFactory != null) {
    25.             WebDataBinder binder = binderFactory.createBinder(webRequest, arg, name);
    26.             if (arg != null) {
    27.                 this.validateIfApplicable(binder, parameter);
    28.                 if (binder.getBindingResult().hasErrors() && this.isBindExceptionRequired(binder, parameter)) {
    29.                     throw new MethodArgumentNotValidException(parameter, binder.getBindingResult());
    30.                 }
    31.             }
    32.             if (mavContainer != null) {
    33.                 mavContainer.addAttribute(BindingResult.MODEL_KEY_PREFIX + name, binder.getBindingResult());
    34.             }
    35.         }
    36.         return this.adaptArgumentIfNecessary(arg, parameter);
    37.     }
    38.     protected Object readWithMessageConverters(NativeWebRequest webRequest, MethodParameter parameter, Type paramType) throws IOException, HttpMediaTypeNotSupportedException, HttpMessageNotReadableException {
    39.         HttpServletRequest servletRequest = (HttpServletRequest)webRequest.getNativeRequest(HttpServletRequest.class);
    40.         Assert.state(servletRequest != null, "No HttpServletRequest");
    41.         ServletServerHttpRequest inputMessage = new ServletServerHttpRequest(servletRequest);
    42.         Object arg = this.readWithMessageConverters(inputMessage, parameter, paramType);
    43.         if (arg == null && this.checkRequired(parameter)) {
    44.             throw new HttpMessageNotReadableException("Required request body is missing: " + parameter.getExecutable().toGenericString(), inputMessage);
    45.         } else {
    46.             return arg;
    47.         }
    48.     }
    49.     protected boolean checkRequired(MethodParameter parameter) {
    50.         RequestBody requestBody = (RequestBody)parameter.getParameterAnnotation(RequestBody.class);
    51.         return requestBody != null && requestBody.required() && !parameter.isOptional();
    52.     }
    53.     public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {
    54.         mavContainer.setRequestHandled(true);
    55.         ServletServerHttpRequest inputMessage = this.createInputMessage(webRequest);
    56.         ServletServerHttpResponse outputMessage = this.createOutputMessage(webRequest);
    57.         this.writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);
    58.     }
    59. }
    60. 6 开启异步线程管理

             走完第五步,基本上SpringMVC的核心流程便已经走完了,这时候如果开启了异步线程,这个请求便直接结束了。

      7 小结


             了解完springMVC的完整流程,可以更好的对基于springboot框架的项目进行自定义开发,也能更好的理解一个功能为什么要这么做。
             比较实际的有,我们可以自定义一系列的拦截器,也了解了它们会在什么时候执行,还可以在进入方法之前对参数和返回值进行自定义处理。
              例如笔者就基于参数和返回值的接口,开发出了一套基于JPA的数据权限管理框架。
              另外的拦截器的作用,对我们理解一些框架的拦截器也很有帮助,比如SpringCache和Mabtis的一些拦截插件。
              最重要的就是,SpringMVC框架中的一些设计思想和设计模式对我们的程序设计有借鉴意义。

    61. 相关阅读:
      Shell 脚本的编写总结
      函数式编程-Stream流笔记-三更草堂
      [前端基础] JavaScript 基础篇(下)
      Ceph块存储
      Android打造一个高性能无限层级显示的树形控件(Android树形控件)
      macOS 上如何写自定义命令行工具?
      安卓开发2年,入职字节跳动那天我哭了,被裁后奋战3个月终拿下
      转录组测序学习第二弹
      设计模式与应用:备忘录模式
      一种改进的鲸鱼优化算法-附代码
    62. 原文地址:https://blog.csdn.net/bigbearxyz/article/details/126385693