SpringMVC源码分析-DispatcherServlet-接收请求流程

上一篇:SpringMVC源码分析-DispatcherServlet-init方法分析ios

DispatcherServlet的init已经将所须要的各类Resolver准备好,能够说是万事俱备只欠东风了,下面就看看它是如何接收请求,并将请求映射到Controller上的方法,而后将返回值格式化为字符串或者使用视图解析器完成解析的web

时序图

概要说明

前半部分画了从Tomcat最后一个阀门(Valve)如何一步步调用到DispatcherServlet的doService方法。json

后半部分画了SpringMVC的处理流程,以下:后端

在DispatcherServlet中调用getHandler()获得符合条件的HandlerMapping(如:RequestMappingRequestHandler-请求参数解析、绑定。。。在这里面还会降将该请求适合的Interceptors与handler一块儿封装为一个HandlerExecutionChain),接着根据获得的HandlerMapping调用getHandlerAdpater()获得符合条件的HandlerAdapter(如:RequestMappingHandlerAdapter-调用Controller中的方法,返回值格式化,肯定ModleAndView),在调用Controller以前执行拦截器的preHandle(),调用再接着调用HandlerAdapter的handle方法,在调用Contoller以后执行拦截器的postHandle()方法,最后调用processDispatchResult()根据MV执行转发浏览器

源码分析

DispatcherServlet-doDispatchapp

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 {
                processedRequest = checkMultipart(request);//文件上传,转换request为mutipart request
                multipartRequestParsed = (processedRequest != request);
​
                // 决定当前请求使用的最优Handler,也就是说根据请求路径去找到Controller中的某一个方法
                mappedHandler = getHandler(processedRequest);
                if (mappedHandler == null) {
                    noHandlerFound(processedRequest, response);
                    return;
                }
​
                // 根据mappedHanler中的HandlerMethod决定当前请求要使用的HandlerAdpater,好比RequestMappingHandlerAdapter
                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)) {
                    //getLastModified该方法都是返回-1,也不知道具体是干什么用的。感受像是判断Mapping是否改变了,也许和热加载有关系吧
                    long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
                    if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
                        return;
                    }
                }
                //Invoke前处理--百度一大把SpringMVC请求流程中的讲到的东西
                if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                    return;
                }
​
                // 真正invoke Handler对应的方法或者其余对象,会完成参数绑定、方法调用、返回参数格式化等操做
                mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
​
                if (asyncManager.isConcurrentHandlingStarted()) {
                    return;
                }
​
                applyDefaultViewName(processedRequest, mv);
                //Invoke后处理
                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);
            }
            /**
             * 处理由前面选择的处理器(mappedHandler)和处理器(HandlerAdapter)调用的结果:就是一个正常或者一个异常的MV
             * 而后再调用triggerAfterCompletion
             * 下面的两个异常逻辑也须要调用triggerAfterCompletion
             *
             *
             */
            processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
        }
        catch (Exception ex) {
            //异常-触发“完成后”处理
            triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
        }
        catch (Throwable err) {
            //异常-触发“完成后”处理
            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);
                }
            }
        }
    }

获取Handler(HandlerExecutionChain)

DispatcherServlet.getHandle()前后端分离

protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
        if (this.handlerMappings != null) {
            /**
             * 循环全部的HandlerMappings,找到合适的HandlerMethod或者其余类型的Handler
             * 将找到的Handler与拦截器一块儿封装一个HandlerExecutionChain
             * 下面看看RequestMappingHandlerMapping的getHandler方法
             */
            for (HandlerMapping mapping : this.handlerMappings) {
                HandlerExecutionChain handler = mapping.getHandler(request);
                if (handler != null) {
                    return handler;
                }
            }
        }
        return null;
    }

RequestMappingHandlerMapping.getHandler(),最终会调用到它父类AbstractHandlerMethodMapping的getHandlerInternal()async

protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
        String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
        request.setAttribute(LOOKUP_PATH, lookupPath);
        this.mappingRegistry.acquireReadLock();
        try {
            //从HandlerMappings当中找到一个最优匹配的Handler(MethodHandler)
            HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
            return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
        }
        finally {
            this.mappingRegistry.releaseReadLock();
        }
    }

上面的代码再调用AbstractHandlerMethodMapping的lookupHandlerMethod方法ide

protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
        List<Match> matches = new ArrayList<>();
        /**
         * mappingRegistry当中有一个urlLookup的Map,里面存放的是全部以目录形式访问的路径对应的RequestMappingInfo
         * 好比:/testweb/user/query
         *       /testweb/user/save
         * 可是/testweb/user/query/{userName}这种就不行了,经过这个拆分可让更多场景迅速找到惟一的RequestMappingInfo,
         * 减小循环遍历全部的RequestMappingInfos,而后再Compare的耗时
         */
        List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
        if (directPathMatches != null) {
            addMatchingMappings(directPathMatches, matches, request);
        }
        if (matches.isEmpty()) {
            // No choice but to go through all mappings...
            addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request);
        }
​
        if (!matches.isEmpty()) {
            //MatchComparator定义了排序的规则,具体规则就不赘述了,百度一下或者看看RequestMappingInfo的CompareTo方法
            Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
            matches.sort(comparator);
            Match bestMatch = matches.get(0);
            if (matches.size() > 1) {
                if (logger.isTraceEnabled()) {
                    logger.trace(matches.size() + " matching mappings: " + matches);
                }
                if (CorsUtils.isPreFlightRequest(request)) {
                    return PREFLIGHT_AMBIGUOUS_MATCH;
                }
                Match secondBestMatch = 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);
            handleMatch(bestMatch.mapping, lookupPath, request);
            return bestMatch.handlerMethod;
        }
        else {
            return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
        }
    }

获取HandlerAdpter

DispathcerServlet.getHandlerAdapter()源码分析

protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
        if (this.handlerAdapters != null) {
            /**
             * 循环全部的handlerAdpaters,调用它们的supports方法找到匹配的HandlerAdapter
             * 以RequestMappingHandlerAdapter为例看看它的supports方法
             */
            for (HandlerAdapter adapter : this.handlerAdapters) {
                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");
    }

上面的supports方法其实是RequestMappingHandlerAdapter父类AbstractHandlerMethodAdapter的supports

public final boolean supports(Object handler) {
        //supportsInternal()里面竟然就是一个返回一个肯定的true,能够想到,本身能够扩展一个Adapter修改这个方法,更改MVC的默认匹配规则
        return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));
    }

能够很清楚看到这个Adapter就是处理HandlerMethod这类型的Handler

执行拦截的preHandle

boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
        HandlerInterceptor[] interceptors = getInterceptors();
        if (!ObjectUtils.isEmpty(interceptors)) {
            /**
             * 循环执行拦截器的preHandle方法,若是返回值为false,则还要倒序执行拦截的afterCompletion方法
             */
            for (int i = 0; i < interceptors.length; i++) {
                HandlerInterceptor interceptor = interceptors[i];
                if (!interceptor.preHandle(request, response, this.handler)) {
                    triggerAfterCompletion(request, response, null);
                    return false;
                }
                this.interceptorIndex = i;
            }
        }
        return true;
    }

这里面有一个倒序执行拦截器的afterCompletion方法要注意

调用Adapter的handle

在这里重点看底层被调用的

public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
            Object... providedArgs) throws Exception {
        /**
         * 方法里面首先解析参数,选择对的HandlerMethodArgumentResolver,并完成参数值的绑定,好比:
         * RequestParamMethodArgumentResolver负责解析,完成参数绑定。没有注解该Resolver一样适用
         * 由PathVariableMethodArgumentResolver负责解析,完成参数绑定
         * 由RequestBodyMethodArgumentResolver负责解析,完成参数绑定
         */
        Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
        setResponseStatus(webRequest);
        。。。。省略部分代码。。。。。
        try {
            /**
             * 根据返回类型以及方法的注解判断才用那个HandlerMethodReturnValueHandler来处理返回值
             *
             *
             *
             *
             *
             */
            this.returnValueHandlers.handleReturnValue(
                    returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
        }
        catch (Exception ex) {
            if (logger.isTraceEnabled()) {
                logger.trace(formatErrorForReturnValue(returnValue), ex);
            }
            throw ex;
        }
    }

returnValueHandlers.handleReturnValue

public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
            ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
        //肯定应该使用的HandlerMethodReturnValueHandler
        HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType);
        if (handler == null) {
            throw new IllegalArgumentException("Unknown return value type: " + returnType.getParameterType().getName());
        }
        //对invoke返回的结果进行处理,好比进行json格式化
        handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
    }

看看debug时handler是谁

再看看对返回结果转换的核心代码,能够看到默认是有前面4个Converter的,最后一个Converter是我经过PostProcessor强行添加进去的

最终由MappingJacksonHttpMessageConverter完成对User对象的Json格式化转换,并将转换结果写到了Response当中

执行拦截器的postHandle

void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv)
            throws Exception {
​
        HandlerInterceptor[] interceptors = getInterceptors();
        if (!ObjectUtils.isEmpty(interceptors)) {
            /**
             * 循环执行拦截器的postHandle方法
             */
            for (int i = interceptors.length - 1; i >= 0; i--) {
                HandlerInterceptor interceptor = interceptors[i];
                interceptor.postHandle(request, response, this.handler, mv);
            }
        }
    }

 

执行跳转

 

private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
            @Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
            @Nullable Exception exception) throws Exception {
​
        boolean errorView = false;
        //异常MV处理
        if (exception != null) {
            if (exception instanceof ModelAndViewDefiningException) {
                logger.debug("ModelAndViewDefiningException encountered", exception);
                mv = ((ModelAndViewDefiningException) exception).getModelAndView();
            }
            else {
                Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
                //在这里可使用自定义的ExceptionHandlerResolver对异常MV进行处理
                mv = processHandlerException(request, response, handler, exception);
                errorView = (mv != null);
            }
        }
​
        //渲染Handler返回的MV,渲染没有深刻去看,由于如今流行先后端分离,几乎都是返回的JSON串回去
        if (mv != null && !mv.wasCleared()) {
            render(mv, request, response);
            if (errorView) {
                WebUtils.clearErrorRequestAttributes(request);
            }
        }
        。。。省略部分代码。。。
​
        if (mappedHandler != null) {
            // 最后执行afterCompletion方法
            mappedHandler.triggerAfterCompletion(request, response, null);
        }
    }

最后只有执行完Tomcat的CoyoteAdapter.service中的以下两行代码浏览器才会收到返回值

request.finishRequest();
 response.finishResponse();

总结

DispatcherServlet接收请求的处理流程涉及到几个很是重要的扩展点,自定义HandlerMapping、自定义HandlerAdapter,一般SpringMVC是不建议开发者去修改最底层的内容的,可是SpringMVC容许且建议开发者能够修改默认的HandlerMapping与HandlerAdpater当中属性中的值,好比给Adapter添加argumentResolvers,initBinderArgumentResolvers,returnValueHandlers,MessageConverters等等

除了上面的内容,固然还有常常用到的一点就是Interceptor在HandlerAdapter.handle()以前的preHandle与以后postHandle,以及afterCompletion。须要注意preHandle的返回值为false时会倒序调用拦截器中的afterCompletion方法

 

SpringMVC源码复杂度和Spring比起来,前者仍是要轻松一些,总的来讲在Tomcat启动的时候调用DispatcherServlet.init方法经过Spring容器完成了全部默认组件与配置类的实例化与参数的加载,开发者能够经过Spring提供的BeanPostProcessor修改这些默认类的实例化过程,修改它们的属性值和行为,而后在完成Dispatcher.init以后经过servlet规范调用到DispatcherServlet的service方法,经过以前已经实例化的组件与配置类实例共同做用完成了从请求到Controller的执行与返回浏览器的过程

接下来去开启SpringBoot的源码分析

相关文章
相关标签/搜索