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层,找到指定的方法,执行便完了。
那么其具体的细节到底是怎样的,我们通过源码来一步步的进行深究。

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
        HttpServletRequest processedRequest = request;
        HandlerExecutionChain mappedHandler = null;
        boolean multipartRequestParsed = false;
        //1设置异步线程管理
        WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
        try {
            try {
                ModelAndView mv = null;
                Object dispatchException = null;
                try {
                    //2判断是否是一个文件上传请求
                    processedRequest = this.checkMultipart(request);
                    multipartRequestParsed = processedRequest != request;
                    //3获取符合条件的mappedHandler
                    mappedHandler = this.getHandler(processedRequest);
                    if (mappedHandler == null) {
                        this.noHandlerFound(processedRequest, response);
                        return;
                    }
                    //4获取HandlerAdapter
                    HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());
                    String method = request.getMethod();
                    boolean isGet = "GET".equals(method);
                    if (isGet || "HEAD".equals(method)) {
                        long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
                        if ((new ServletWebRequest(request, response)).checkNotModified(lastModified) && isGet) {
                            return;
                        }
                    }
                    if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                        return;
                    }
                    //5获取ModelAndView
                    mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
                    //6开启异步线程管理
                    if (asyncManager.isConcurrentHandlingStarted()) {
                        return;
                    }
                    this.applyDefaultViewName(processedRequest, mv);
                    mappedHandler.applyPostHandle(processedRequest, response, mv);
                } catch (Exception var20) {
                    dispatchException = var20;
                } catch (Throwable var21) {
                    dispatchException = new NestedServletException("Handler dispatch failed", var21);
                }
                this.processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException);
            } catch (Exception var22) {
                this.triggerAfterCompletion(processedRequest, response, mappedHandler, var22);
            } catch (Throwable var23) {
                this.triggerAfterCompletion(processedRequest, response, mappedHandler, new NestedServletException("Handler processing failed", var23));
            }
        } finally {
            if (asyncManager.isConcurrentHandlingStarted()) {
                if (mappedHandler != null) {
                    mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
                }
            } else if (multipartRequestParsed) {
                this.cleanupMultipart(processedRequest);
            }
        }
    }

   

 1 异步线程管理WebAsyncManager


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


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


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

 3 获取符合条件的mappedHandler


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

protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
        if (this.handlerMappings != null) {
            Iterator var2 = this.handlerMappings.iterator();
            while(var2.hasNext()) {
                HandlerMapping mapping = (HandlerMapping)var2.next();
                HandlerExecutionChain handler = mapping.getHandler(request);
                if (handler != null) {
                    return handler;
                }
            }
        }
        return null;
    }

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


  3.1 什么是handlerMappings


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

public interface HandlerMapping {
        String BEST_MATCHING_HANDLER_ATTRIBUTE = HandlerMapping.class.getName() + ".bestMatchingHandler";
        String LOOKUP_PATH = HandlerMapping.class.getName() + ".lookupPath";
        String PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE = HandlerMapping.class.getName() + ".pathWithinHandlerMapping";
        String BEST_MATCHING_PATTERN_ATTRIBUTE = HandlerMapping.class.getName() + ".bestMatchingPattern";
        String INTROSPECT_TYPE_LEVEL_MAPPING = HandlerMapping.class.getName() + ".introspectTypeLevelMapping";
        String URI_TEMPLATE_VARIABLES_ATTRIBUTE = HandlerMapping.class.getName() + ".uriTemplateVariables";
        String MATRIX_VARIABLES_ATTRIBUTE = HandlerMapping.class.getName() + ".matrixVariables";
        String PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE = HandlerMapping.class.getName() + ".producibleMediaTypes";

        @Nullable
        HandlerExecutionChain getHandler(HttpServletRequest var1) throws Exception;
    }

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


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

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

protected void initStrategies(ApplicationContext context) {
        this.initMultipartResolver(context);
        this.initLocaleResolver(context);
        this.initThemeResolver(context);
        this.initHandlerMappings(context);
        this.initHandlerAdapters(context);
        this.initHandlerExceptionResolvers(context);
        this.initRequestToViewNameTranslator(context);
        this.initViewResolvers(context);
        this.initFlashMapManager(context);
    }

  其具体方法如下:    

private void initHandlerMappings(ApplicationContext context) {
        this.handlerMappings = null;
        if (this.detectAllHandlerMappings) {
            Map<String, HandlerMapping> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
            if (!matchingBeans.isEmpty()) {
                this.handlerMappings = new ArrayList(matchingBeans.values());
                AnnotationAwareOrderComparator.sort(this.handlerMappings);
            }
        } else {
            try {
                HandlerMapping hm = (HandlerMapping)context.getBean("handlerMapping", HandlerMapping.class);
                this.handlerMappings = Collections.singletonList(hm);
            } catch (NoSuchBeanDefinitionException var3) {
            }
        }

        if (this.handlerMappings == null) {
            this.handlerMappings = this.getDefaultStrategies(context, HandlerMapping.class);
            if (this.logger.isTraceEnabled()) {
                this.logger.trace("No HandlerMappings declared for servlet '" + this.getServletName() + "': using default strategies from DispatcherServlet.properties");
            }
        }

    }

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

  public static <T> Map<String, T> beansOfTypeIncludingAncestors(ListableBeanFactory lbf, Class<T> type, boolean includeNonSingletons, boolean allowEagerInit) throws BeansException {
        Assert.notNull(lbf, "ListableBeanFactory must not be null");
        Map<String, T> result = new LinkedHashMap(4);
        result.putAll(lbf.getBeansOfType(type, includeNonSingletons, allowEagerInit));
        if (lbf instanceof HierarchicalBeanFactory) {
            HierarchicalBeanFactory hbf = (HierarchicalBeanFactory)lbf;
            if (hbf.getParentBeanFactory() instanceof ListableBeanFactory) {
                Map<String, T> parentResult = beansOfTypeIncludingAncestors((ListableBeanFactory)hbf.getParentBeanFactory(), type, includeNonSingletons, allowEagerInit);
                parentResult.forEach((beanName, beanInstance) -> {
                    if (!result.containsKey(beanName) && !hbf.containsLocalBean(beanName)) {
                        result.put(beanName, beanInstance);
                    }

                });
            }
        }

        return result;
    }


    总结上面的代码便是,通过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方法,也就是:    

@Nullable
    public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
        Object handler = this.getHandlerInternal(request);
        if (handler == null) {
            handler = this.getDefaultHandler();
        }
        if (handler == null) {
            return null;
        } else {
            if (handler instanceof String) {
                String handlerName = (String)handler;
                handler = this.obtainApplicationContext().getBean(handlerName);
            }

            HandlerExecutionChain executionChain = this.getHandlerExecutionChain(handler, request);
            if (this.logger.isTraceEnabled()) {
                this.logger.trace("Mapped to " + handler);
            } else if (this.logger.isDebugEnabled() && !request.getDispatcherType().equals(DispatcherType.ASYNC)) {
                this.logger.debug("Mapped to " + executionChain.getHandler());
            }

            if (this.hasCorsConfigurationSource(handler) || CorsUtils.isPreFlightRequest(request)) {
                CorsConfiguration config = this.corsConfigurationSource != null ? this.corsConfigurationSource.getCorsConfiguration(request) : null;
                CorsConfiguration handlerConfig = this.getCorsConfiguration(handler, request);
                config = config != null ? config.combine(handlerConfig) : handlerConfig;
                executionChain = this.getCorsHandlerExecutionChain(request, executionChain, config);
            }

            return executionChain;
        }
    }

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


 3.2.1 怎么返回不为空的handler


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

protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
        request.removeAttribute(PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE);
        HandlerMethod var2;
        try {
            var2 = super.getHandlerInternal(request);
        } finally {
            ProducesRequestCondition.clearMediaTypesAttribute(request);
        }
        return var2;
    }

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

protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
        //计算出请求路径
        String lookupPath = this.getUrlPathHelper().getLookupPathForRequest(request);
        request.setAttribute(LOOKUP_PATH, lookupPath);
        //设置读锁
        this.mappingRegistry.acquireReadLock();
        HandlerMethod var4;
        try {
            //根据request参数,找到对应controller层方法
            HandlerMethod handlerMethod = this.lookupHandlerMethod(lookupPath, request);
            var4 = handlerMethod != null ? handlerMethod.createWithResolvedBean() : null;
        } finally {
            //释放锁
            this.mappingRegistry.releaseReadLock();
        }
        return var4;
    }


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

protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
        List<AbstractHandlerMethodMapping<T>.Match> matches = new ArrayList();
        //根据路径去集合中查找到所有满足条件的路径集合
        List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
        if (directPathMatches != null) {
        //根据路径集合去找可能满足条件的方法matches
            this.addMatchingMappings(directPathMatches, matches, request);
        }

        if (matches.isEmpty()) {
            this.addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request);
        }

        if (!matches.isEmpty()) {
            AbstractHandlerMethodMapping<T>.Match bestMatch = (AbstractHandlerMethodMapping.Match)matches.get(0);
            if (matches.size() > 1) {
                Comparator<AbstractHandlerMethodMapping<T>.Match> comparator = new AbstractHandlerMethodMapping.MatchComparator(this.getMappingComparator(request));
                matches.sort(comparator);
                bestMatch = (AbstractHandlerMethodMapping.Match)matches.get(0);
                if (this.logger.isTraceEnabled()) {
                    this.logger.trace(matches.size() + " matching mappings: " + matches);
                }

                if (CorsUtils.isPreFlightRequest(request)) {
                    return PREFLIGHT_AMBIGUOUS_MATCH;
                }

                AbstractHandlerMethodMapping<T>.Match secondBestMatch = (AbstractHandlerMethodMapping.Match)matches.get(1);
                if (comparator.compare(bestMatch, secondBestMatch) == 0) {
                    Method m1 = bestMatch.handlerMethod.getMethod();
                    Method m2 = secondBestMatch.handlerMethod.getMethod();
                    String uri = request.getRequestURI();
                    throw new IllegalStateException("Ambiguous handler methods mapped for '" + uri + "': {" + m1 + ", " + m2 + "}");
                }
            }

            request.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, bestMatch.handlerMethod);
            //找到最合适的方法返回
            this.handleMatch(bestMatch.mapping, lookupPath, request);
            return bestMatch.handlerMethod;
        } else {
            return this.handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
        }
    }

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

public HandlerMethod createWithResolvedBean() {
        //controller层的bean名称
        Object handler = this.bean;
        if (this.bean instanceof String) {
            Assert.state(this.beanFactory != null, "Cannot resolve bean name without BeanFactory");
            //获取beanName
            String beanName = (String)this.bean;
            //通过beanName,从ioc容器获取真正的bean
            handler = this.beanFactory.getBean(beanName);
        }
        //构造HandlerMethod
        return new HandlerMethod(this, handler);
    }

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


  3.2.2 为什么别的Mapping不满足


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

 @Nullable
    protected Object getHandlerInternal(HttpServletRequest request) throws Exception {
        String lookupPath = this.getUrlPathHelper().getLookupPathForRequest(request);
        request.setAttribute(LOOKUP_PATH, lookupPath);
        Object handler = this.lookupHandler(lookupPath, request);
        if (handler == null) {
            Object rawHandler = null;
            if ("/".equals(lookupPath)) {
                rawHandler = this.getRootHandler();
            }

            if (rawHandler == null) {
                rawHandler = this.getDefaultHandler();
            }

            if (rawHandler != null) {
                if (rawHandler instanceof String) {
                    String handlerName = (String)rawHandler;
                    rawHandler = this.obtainApplicationContext().getBean(handlerName);
                }

                this.validateHandler(rawHandler, request);
                handler = this.buildPathExposingHandler(rawHandler, lookupPath, lookupPath, (Map)null);
            }
        }

        return handler;
    }

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

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

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


  3.2.3 返回HandlerExecutionChain
    

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

 protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
        HandlerExecutionChain chain = handler instanceof HandlerExecutionChain ? (HandlerExecutionChain)handler : new HandlerExecutionChain(handler);
        String lookupPath = this.urlPathHelper.getLookupPathForRequest(request, LOOKUP_PATH);
        Iterator var5 = this.adaptedInterceptors.iterator();

        while(var5.hasNext()) {
            HandlerInterceptor interceptor = (HandlerInterceptor)var5.next();
            if (interceptor instanceof MappedInterceptor) {
                MappedInterceptor mappedInterceptor = (MappedInterceptor)interceptor;
                if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
                    chain.addInterceptor(mappedInterceptor.getInterceptor());
                }
            } else {
                chain.addInterceptor(interceptor);
            }
        }

        return chain;
    }

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

public class HandlerExecutionChain {
    private static final Log logger = LogFactory.getLog(HandlerExecutionChain.class);
    private final Object handler;
    @Nullable
    private HandlerInterceptor[] interceptors;
    @Nullable
    private List<HandlerInterceptor> interceptorList;
    private int interceptorIndex;

    public HandlerExecutionChain(Object handler) {
        this(handler, (HandlerInterceptor[])null);
    }
    ......

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


 4 获取HandlerAdapter


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

  protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
        if (this.handlerAdapters != null) {
            Iterator var2 = this.handlerAdapters.iterator();
            while(var2.hasNext()) {
                HandlerAdapter adapter = (HandlerAdapter)var2.next();
                if (adapter.supports(handler)) {
                    return adapter;
                }
            }
        }
        throw new ServletException("No adapter for handler [" + handler + "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
    }

   


    4.1什么是HandlerAdapter


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

     public interface HandlerAdapter {
        boolean supports(Object var1);
        @Nullable
        ModelAndView handle(HttpServletRequest var1, HttpServletResponse var2, Object var3) throws Exception;
        long getLastModified(HttpServletRequest var1, Object var2);
    }

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


    4.2List<HandlerAdapter>的初始化


        和第三步类似,在同一个类中,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    

public abstract class AbstractHandlerMethodAdapter extends WebContentGenerator implements HandlerAdapter, Ordered {
    private int order = 2147483647;
    public AbstractHandlerMethodAdapter() {
        super(false);
    }
    public void setOrder(int order) {
        this.order = order;
    }
    public int getOrder() {
        return this.order;
    }
    public final boolean supports(Object handler) {
        return handler instanceof HandlerMethod && this.supportsInternal((HandlerMethod)handler);
    }
     ......
      protected boolean supportsInternal(HandlerMethod handlerMethod) {
        return true;
    }

       其实我们可以看到,最后的一个适配器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:    

protected ModelAndView handleInternal(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
        this.checkRequest(request);
        ModelAndView mav;
        if (this.synchronizeOnSession) {
            HttpSession session = request.getSession(false);
            if (session != null) {
                Object mutex = WebUtils.getSessionMutex(session);
                synchronized(mutex) {
                    mav = this.invokeHandlerMethod(request, response, handlerMethod);
                }
            } else {
                mav = this.invokeHandlerMethod(request, response, handlerMethod);
            }
        } else {
            mav = this.invokeHandlerMethod(request, response, handlerMethod);
        }
        if (!response.containsHeader("Cache-Control")) {
            if (this.getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
                this.applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
            } else {
                this.prepareResponse(response);
            }
        }
        return mav;
    }

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

protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
        ServletWebRequest webRequest = new ServletWebRequest(request, response);

        ModelAndView var15;
        try {
            WebDataBinderFactory binderFactory = this.getDataBinderFactory(handlerMethod);
            ModelFactory modelFactory = this.getModelFactory(handlerMethod, binderFactory);
            ServletInvocableHandlerMethod invocableMethod = this.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);
            Object result;
            if (asyncManager.hasConcurrentResult()) {
                result = asyncManager.getConcurrentResult();
                mavContainer = (ModelAndViewContainer)asyncManager.getConcurrentResultContext()[0];
                asyncManager.clearConcurrentResult();
                LogFormatUtils.traceDebug(this.logger, (traceOn) -> {
                    String formatted = LogFormatUtils.formatValue(result, !traceOn);
                    return "Resume with async result [" + formatted + "]";
                });
                invocableMethod = invocableMethod.wrapConcurrentResult(result);
            }

            invocableMethod.invokeAndHandle(webRequest, mavContainer, new Object[0]);
            if (asyncManager.isConcurrentHandlingStarted()) {
                result = null;
                return (ModelAndView)result;
            }

            var15 = this.getModelAndView(mavContainer, modelFactory, webRequest);
        } finally {
            webRequest.requestCompleted();
        }

        return var15;
    }

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

 public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
        //第一步和第二步集成方法
        Object returnValue = this.invokeForRequest(webRequest, mavContainer, providedArgs);
        this.setResponseStatus(webRequest);
        if (returnValue == null) {
            if (this.isRequestNotModified(webRequest) || this.getResponseStatus() != null || mavContainer.isRequestHandled()) {
                this.disableContentCachingIfNecessary(webRequest);
                mavContainer.setRequestHandled(true);
                return;
            }
        } else if (StringUtils.hasText(this.getResponseStatusReason())) {
            mavContainer.setRequestHandled(true);
            return;
        }

        mavContainer.setRequestHandled(false);
        Assert.state(this.returnValueHandlers != null, "No return value handlers");

        try {
            //第三步处理返回数据
            this.returnValueHandlers.handleReturnValue(returnValue, this.getReturnValueType(returnValue), mavContainer, webRequest);
        } catch (Exception var6) {
            if (this.logger.isTraceEnabled()) {
                this.logger.trace(this.formatErrorForReturnValue(returnValue), var6);
            }

            throw var6;
        }
    }
 @Nullable
    public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
        //第一步,获取方法参数
        Object[] args = this.getMethodArgumentValues(request, mavContainer, providedArgs);
        if (this.logger.isTraceEnabled()) {
            this.logger.trace("Arguments: " + Arrays.toString(args));
        }
        //第二步,执行方法
        return this.doInvoke(args);
    }

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


  5.1 获取方法参数

    

protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
        MethodParameter[] parameters = this.getMethodParameters();
        if (ObjectUtils.isEmpty(parameters)) {
            return EMPTY_ARGS;
        } else {
            Object[] args = new Object[parameters.length];

            for(int i = 0; i < parameters.length; ++i) {
                MethodParameter parameter = parameters[i];
                parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
                args[i] = findProvidedArgument(parameter, providedArgs);
                if (args[i] == null) {
                    if (!this.resolvers.supportsParameter(parameter)) {
                        throw new IllegalStateException(formatArgumentError(parameter, "No suitable resolver"));
                    }

                    try {
                        //解析每一个参数
                        args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
                    } catch (Exception var10) {
                        if (this.logger.isDebugEnabled()) {
                            String exMsg = var10.getMessage();
                            if (exMsg != null && !exMsg.contains(parameter.getExecutable().toGenericString())) {
                                this.logger.debug(formatArgumentError(parameter, exMsg));
                            }
                        }

                        throw var10;
                    }
                }
            }

            return args;
        }
    }

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

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

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

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

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

public class PathVariableMapMethodArgumentResolver implements HandlerMethodArgumentResolver {
        public PathVariableMapMethodArgumentResolver() {
        }
        public boolean supportsParameter(MethodParameter parameter) {
            PathVariable ann = (PathVariable)parameter.getParameterAnnotation(PathVariable.class);
            return ann != null && Map.class.isAssignableFrom(parameter.getParameterType()) && !StringUtils.hasText(ann.value());
        }
        public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
            Map<String, String> uriTemplateVars = (Map)webRequest.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, 0);
            return !CollectionUtils.isEmpty(uriTemplateVars) ? new LinkedHashMap(uriTemplateVars) : Collections.emptyMap();
        }
    }


  5.2 处理返回数据


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

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

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

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

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

 public class RequestResponseBodyMethodProcessor extends AbstractMessageConverterMethodProcessor {
    public RequestResponseBodyMethodProcessor(List<HttpMessageConverter<?>> converters) {
        super(converters);
    }
    public RequestResponseBodyMethodProcessor(List<HttpMessageConverter<?>> converters, @Nullable ContentNegotiationManager manager) {
        super(converters, manager);
    }
    public RequestResponseBodyMethodProcessor(List<HttpMessageConverter<?>> converters, @Nullable List<Object> requestResponseBodyAdvice) {
        super(converters, (ContentNegotiationManager)null, requestResponseBodyAdvice);
    }
    public RequestResponseBodyMethodProcessor(List<HttpMessageConverter<?>> converters, @Nullable ContentNegotiationManager manager, @Nullable List<Object> requestResponseBodyAdvice) {
        super(converters, manager, requestResponseBodyAdvice);
    }
    public boolean supportsParameter(MethodParameter parameter) {
        return parameter.hasParameterAnnotation(RequestBody.class);
    }
    public boolean supportsReturnType(MethodParameter returnType) {
        return AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), ResponseBody.class) || returnType.hasMethodAnnotation(ResponseBody.class);
    }
    public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
        parameter = parameter.nestedIfOptional();
        Object arg = this.readWithMessageConverters(webRequest, parameter, parameter.getNestedGenericParameterType());
        String name = Conventions.getVariableNameForParameter(parameter);
        if (binderFactory != null) {
            WebDataBinder binder = binderFactory.createBinder(webRequest, arg, name);
            if (arg != null) {
                this.validateIfApplicable(binder, parameter);
                if (binder.getBindingResult().hasErrors() && this.isBindExceptionRequired(binder, parameter)) {
                    throw new MethodArgumentNotValidException(parameter, binder.getBindingResult());
                }
            }

            if (mavContainer != null) {
                mavContainer.addAttribute(BindingResult.MODEL_KEY_PREFIX + name, binder.getBindingResult());
            }
        }

        return this.adaptArgumentIfNecessary(arg, parameter);
    }
    protected <T> Object readWithMessageConverters(NativeWebRequest webRequest, MethodParameter parameter, Type paramType) throws IOException, HttpMediaTypeNotSupportedException, HttpMessageNotReadableException {
        HttpServletRequest servletRequest = (HttpServletRequest)webRequest.getNativeRequest(HttpServletRequest.class);
        Assert.state(servletRequest != null, "No HttpServletRequest");
        ServletServerHttpRequest inputMessage = new ServletServerHttpRequest(servletRequest);
        Object arg = this.readWithMessageConverters(inputMessage, parameter, paramType);
        if (arg == null && this.checkRequired(parameter)) {
            throw new HttpMessageNotReadableException("Required request body is missing: " + parameter.getExecutable().toGenericString(), inputMessage);
        } else {
            return arg;
        }
    }
    protected boolean checkRequired(MethodParameter parameter) {
        RequestBody requestBody = (RequestBody)parameter.getParameterAnnotation(RequestBody.class);
        return requestBody != null && requestBody.required() && !parameter.isOptional();
    }
    public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {
        mavContainer.setRequestHandled(true);
        ServletServerHttpRequest inputMessage = this.createInputMessage(webRequest);
        ServletServerHttpResponse outputMessage = this.createOutputMessage(webRequest);
        this.writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);
    }
}

6 开启异步线程管理

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

7 小结


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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值