美文网首页一些收藏
[Spring MVC]Spring MVC是如何处理请求的

[Spring MVC]Spring MVC是如何处理请求的

作者: AbstractCulture | 来源:发表于2021-12-13 00:55 被阅读0次

    思路

    将HandlerMapping进行初始化后,Spring就会根据请求路径找到对应的Controller方法,进行完Data Binding后执行方法处理请求,然后返回ModelAndView.

    UML

    HandlerMapping

    RequestHandlerMapping间接实现了HandlerMapping接口,其中比较关键的方法就是org.springframework.web.servlet.HandlerMapping#getHandler

    HandlerMapping

    public interface HandlerMapping {
        @Nullable
        HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;
    
    }
    

    HandleMapping接口声明了一个方法getHandler,返回HandlerExecutionChain实例.
    这里不直接返回Handler实例返回HandlerExecutionChain主要是因为要经过一些拦截器,最后才给到handler去响应。
    实现该接口方法的主要是由抽象类-AbstractHandlerMapping去实现的.

    HandlerExecutionChain

    public class HandlerExecutionChain {
    
        private static final Log logger = LogFactory.getLog(HandlerExecutionChain.class);
        // handler实例
        private final Object handler;
    
        @Nullable
        /**
         * 拦截器数组
         */
        private HandlerInterceptor[] interceptors;
    
        @Nullable
        private List<HandlerInterceptor> interceptorList;
    
        private int interceptorIndex = -1;
    }
    

    执行请求的过程-doDispatch

    这里我们编写一个简单的controller,然后进行断点debug来看看Spring执行请求的调用链.

    请求

    由于所有的请求都会经过DispatcherServlet,通常开发者可以通过xml或者注解来达到这个目的,这里不展开说,有兴趣的可以查阅Spring官方文档或者其他的blog.

    • 注解形式
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.HttpServlet;
    
    @WebServlet("/*")
    public class DispatcherServlet extends HttpServlet {
    
    }
    
    • web.xml
    <web-app>
    
        <listener>
            <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
        </listener>
    
        <context-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>/WEB-INF/root-context.xml</param-value>
        </context-param>
    
        <servlet>
            <servlet-name>app1</servlet-name>
            <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
            <init-param>
                <param-name>contextConfigLocation</param-name>
                <param-value>/WEB-INF/app1-context.xml</param-value>
            </init-param>
            <load-on-startup>1</load-on-startup>
        </servlet>
    
        <servlet-mapping>
            <servlet-name>app1</servlet-name>
            <url-pattern>/app1/*</url-pattern>
        </servlet-mapping>
    
    </web-app>
    

    官方文档链接: 点我前往

    经过层层的调用,最终会调用到org.springframework.web.servlet.DispatcherServlet#doDispatch这里.

    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);
                multipartRequestParsed = (processedRequest != request);
    
                // Determine handler for the current request.
                // 判断当前请求对应的handler
                // handler中包含了请求url,以及对应的controller
                mappedHandler = getHandler(processedRequest);
                if (mappedHandler == null) {
                    noHandlerFound(processedRequest, response);
                    return;
                }
    
                // Determine handler adapter for the current request.
                // 根据当前handler获取对应的适配器,adapter用于完成参数解析
                HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
    
                // Process last-modified header, if supported by the handler.
                // 处理GET、HEAD请求的Last-modified
                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;
                    }
                }
                // 遍历所有定义的interceptor,执行preHandle方法
                // 通常是一些拦截器的操作
                if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                    return;
                }
    
                // Actually invoke the handler.
                // 调用目标Controller的方法
                mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
    
                if (asyncManager.isConcurrentHandlingStarted()) {
                    return;
                }
                // 处理成默认视图名,也就是添加前缀和后缀
                applyDefaultViewName(processedRequest, mv);
                // 拦截器postHandle方法进行处理
                mappedHandler.applyPostHandle(processedRequest, response, mv);
            }
            catch (Exception ex) {
                dispatchException = ex;
            }
            catch (Throwable err) {
                // As of 4.3, we're processing Errors thrown from handler methods as well,
                // making them available for @ExceptionHandler methods and other scenarios.
                dispatchException = new NestedServletException("Handler dispatch failed", err);
            }
            // 处理最后的结果,渲染之类的逻辑在这里
            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);
                }
            }
        }
    }
    

    我们来拆解doDispatch的一些关键步骤:

    doDispatch
    • handler
    handler

    getHandler

    getHandler

    可以看到,关于HanlerExecutionChain的Bean有RequestMappingHandlerMapping,我们只需要关注它可以,因为它提供的正是解析@RequestMapping注解的能力.

    RequestMappingHandlerMapping#getHandler
    • org.springframework.web.servlet.handler.AbstractHandlerMapping#getHandler
    public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
        // 获取handler的具体逻辑,留给子类实现
        Object handler = getHandlerInternal(request);
        if (handler == null) {
            // 如果获取到的handler为null,则采用默认的handler,即属性defaultHandler
            handler = getDefaultHandler();
        }
        if (handler == null) {
            // 如果连defaultHandler也为空,则直接返回空
            return null;
        }
        // Bean name or resolved handler?
        // 如果handler是beanName,则需要将beanName转成Bean.
        if (handler instanceof String) {
            String handlerName = (String) handler;
            handler = obtainApplicationContext().getBean(handlerName);
        }
    
        HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
    
        if (logger.isTraceEnabled()) {
            logger.trace("Mapped to " + handler);
        }
        else if (logger.isDebugEnabled() && !request.getDispatcherType().equals(DispatcherType.ASYNC)) {
            logger.debug("Mapped to " + executionChain.getHandler());
        }
    
        if (CorsUtils.isCorsRequest(request)) {
            CorsConfiguration globalConfig = this.corsConfigurationSource.getCorsConfiguration(request);
            CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
            CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);
            executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
        }
    
        return executionChain;
    }
    

    获取当前请求的路径所对应的Handler.

    • org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#getHandlerInternal
    protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
        // lookupPath就是请求路径
        String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
        this.mappingRegistry.acquireReadLock();
        try {
            // 根据路径获取Handler,并封装成HandlerMethod
            HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
            // 根据HandlerMethod中的bean来实力化Handler,并添加到HanlderMethod里面
            return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
        }
        finally {
            this.mappingRegistry.releaseReadLock();
        }
    }
    
    • org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#lookupHandlerMethod
    protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
        List<Match> matches = new ArrayList<>();
        // 通过lookupPath属性查找对应的RequestMappingInfo
        List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
        if (directPathMatches != null) {
            // 如果匹配,检查其他属性是否符合,如请求方法,参数,header等
            addMatchingMappings(directPathMatches, matches, request);
        }
        if (matches.isEmpty()) {
            // No choice but to go through all mappings...
            // 如果没有匹配到,则遍历所有的处理方法进行通配符匹配
            addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request);
        }
    
        if (!matches.isEmpty()) {
            // 如果方法有多个匹配,不同的通配符等,则排序选择出最合适的一个
            Comparator<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参数
            request.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, bestMatch.handlerMethod);
            // 返回匹配的url的处理的方法
            handleMatch(bestMatch.mapping, lookupPath, request);
            return bestMatch.handlerMethod;
        }
        else {
            return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
        }
    }
    

    this.mappingRegistry.getMappingsByUrl(lookupPath);这步,正是通过org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.MappingRegistry#register注册的urlLookup来进行搜索定位的到当前请求的url所对应的RequestMappingInfo的.

    urlLookup

    获取到对应的Controller之后呢,还得继续定位到HandlerMethod.主要是匹配params、headers等参数

    • org.springframework.web.servlet.mvc.method.RequestMappingInfo#getMatchingCondition
    public RequestMappingInfo getMatchingCondition(HttpServletRequest request) {
            RequestMethodsRequestCondition methods = this.methodsCondition.getMatchingCondition(request);
            if (methods == null) {
                return null;
            }
            ParamsRequestCondition params = this.paramsCondition.getMatchingCondition(request);
            if (params == null) {
                return null;
            }
            HeadersRequestCondition headers = this.headersCondition.getMatchingCondition(request);
            if (headers == null) {
                return null;
            }
            ConsumesRequestCondition consumes = this.consumesCondition.getMatchingCondition(request);
            if (consumes == null) {
                return null;
            }
            ProducesRequestCondition produces = this.producesCondition.getMatchingCondition(request);
            if (produces == null) {
                return null;
            }
            PatternsRequestCondition patterns = this.patternsCondition.getMatchingCondition(request);
            if (patterns == null) {
                return null;
            }
            RequestConditionHolder custom = this.customConditionHolder.getMatchingCondition(request);
            if (custom == null) {
                return null;
            }
    
            return new RequestMappingInfo(this.name, patterns,
                    methods, params, headers, consumes, produces, custom.getCondition());
        }
    

    经过层层筛选,获取到了HandlerMethod,也就是此次请求所对应的Handler.

    handler

    DispatcherServlet#getHandlerAdapter

    获取到请求参数对应的Handler后,Spring MVC还需要对参数进行binding.这就会用到适配器去执行这个操作.
    其中,RequestMappingHandlerAdapter就是常用的适配器之一,我们这里只分析它。

    适配器
    • org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter#supports
    public final boolean supports(Object handler) {
        return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));
    }
    

    由于获取的Controller对应的Handler是HandlerMethod的实现类,所以RequestMappingHandlerAdapter是支持解析HandlerMethod的,正如它的javadoc上提示的一样:

    AbstractHandlerMethodAdapter扩展,支持@RequestMapping注释的HandlerMethods 。
    可以通过setCustomArgumentResolvers和setCustomReturnValueHandlers添加对自定义参数和返回值类型的支持,或者重新配置所有参数和返回值类型,使用setArgumentResolvers和setReturnValueHandlers 。
    OK,到了这里,我们主要明确的是,我们一般编写的Controller对应的适配器就是RequestMappingHandlerAdapter.

    HandlerExecutionChain#applyPostHandle

    前面我们说到,为什么设计出HandlerExecutionChain这个包装类,其实不仅仅存储了handler实例,还存储了拦截链,简单理解,是在执行方法前添加了勾子,正如我们平时用的Filter一样.

    AbstractHandlerMethodAdapter#handle

    @Override
    @Nullable
    public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
    
        return handleInternal(request, response, (HandlerMethod) handler);
    }
    

    继续step into.

    protected ModelAndView handleInternal(HttpServletRequest request,
            HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
    
        ModelAndView mav;
        checkRequest(request);
    
        // Execute invokeHandlerMethod in synchronized block if required.
        if (this.synchronizeOnSession) {
            HttpSession session = request.getSession(false);
            if (session != null) {
                Object mutex = WebUtils.getSessionMutex(session);
                synchronized (mutex) {
                    mav = invokeHandlerMethod(request, response, handlerMethod);
                }
            }
            else {
                // No HttpSession available -> no mutex necessary
                mav = invokeHandlerMethod(request, response, handlerMethod);
            }
        }
        else {
            // No synchronization on session demanded at all...
            mav = invokeHandlerMethod(request, response, handlerMethod);
        }
    
        if (!response.containsHeader(HEADER_CACHE_CONTROL)) {
            if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
                applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
            }
            else {
                prepareResponse(response);
            }
        }
    
        return mav;
    }
    

    执行目标Controller的方法.返回ModelView实例.从方法里可以看到,会先对请求做一些校验,进而执行invokeHandlerMethod.

    • org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#invokeHandlerMethod
    protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
            HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
    
        ServletWebRequest webRequest = new ServletWebRequest(request, response);
        try {
            WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
            ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
            // 把handlerMethod封装成ServletInvocableHandlerMethod
            ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
            if (this.argumentResolvers != null) {
                // 设置参数解析器
                invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
            }
            if (this.returnValueHandlers != null) {
                // 设置spring mvc请求controller的method返回值处理器
                invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
            }
            invocableMethod.setDataBinderFactory(binderFactory);
            // 参数名称发现器
            invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
    
            ModelAndViewContainer mavContainer = new ModelAndViewContainer();
            mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
            modelFactory.initModel(webRequest, mavContainer, invocableMethod);
            mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);
    
            AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
            asyncWebRequest.setTimeout(this.asyncRequestTimeout);
    
            WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
            asyncManager.setTaskExecutor(this.taskExecutor);
            asyncManager.setAsyncWebRequest(asyncWebRequest);
            asyncManager.registerCallableInterceptors(this.callableInterceptors);
            asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);
    
            if (asyncManager.hasConcurrentResult()) {
                Object result = asyncManager.getConcurrentResult();
                mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0];
                asyncManager.clearConcurrentResult();
                LogFormatUtils.traceDebug(logger, traceOn -> {
                    String formatted = LogFormatUtils.formatValue(result, !traceOn);
                    return "Resume with async result [" + formatted + "]";
                });
                invocableMethod = invocableMethod.wrapConcurrentResult(result);
            }
            // 执行方法
            invocableMethod.invokeAndHandle(webRequest, mavContainer);
            if (asyncManager.isConcurrentHandlingStarted()) {
                return null;
            }
    
            return getModelAndView(mavContainer, modelFactory, webRequest);
        }
        finally {
            webRequest.requestCompleted();
        }
    }
    

    这里看几个重点:

    1. 参数解析器实例-HandlerMethodArgumentResolvers
    2. 方法返回值处理器实例-HandlerMethodReturnValueHandlers
    3. 参数名称发现器-ParameterNameDiscoverer.
    4. 将这些对象装进ServletInvocableHandlerMethod后,执行方法.
    • org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod#invokeAndHandle
    public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
            Object... providedArgs) throws Exception {
        // 在这里通过反射调用controller中的method
        Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
        setResponseStatus(webRequest);
    
        if (returnValue == null) {
            if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) {
                disableContentCachingIfNecessary(webRequest);
                mavContainer.setRequestHandled(true);
                return;
            }
        }
        else if (StringUtils.hasText(getResponseStatusReason())) {
            mavContainer.setRequestHandled(true);
            return;
        }
    
        mavContainer.setRequestHandled(false);
        Assert.state(this.returnValueHandlers != null, "No return value handlers");
        try {
            // 在这里通过返回值处理器进行二次处理
            // 比如加了@RequestBody注解,那么在这里对结果进行序列化json再返回
            this.returnValueHandlers.handleReturnValue(
                    returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
        }
        catch (Exception ex) {
            if (logger.isTraceEnabled()) {
                logger.trace(formatErrorForReturnValue(returnValue), ex);
            }
            throw ex;
        }
    }
    
    1. 反射调用controller中的method.
      1.1.获取httpRequest中对应的参数.
    2. 通过返回值处理器进行二次处理.比如序列化.
    参数解析
    • org.springframework.web.method.support.InvocableHandlerMethod#getMethodArgumentValues
    protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
            Object... providedArgs) throws Exception {
        // 获取controller方法的参数数组
        MethodParameter[] parameters = getMethodParameters();
        if (ObjectUtils.isEmpty(parameters)) {
            return EMPTY_ARGS;
        }
        // 创建一个参数数组,保存从request中解析出的方法参数
        Object[] args = new Object[parameters.length];
        for (int i = 0; i < parameters.length; i++) {
            MethodParameter parameter = parameters[i];
            // 给每一个Controller方法实例参数初始化一个参数名称发现器
            parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
            args[i] = findProvidedArgument(parameter, providedArgs);
            if (args[i] != null) {
                continue;
            }
            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 ex) {
                // Leave stack trace for later, exception may actually be resolved and handled...
                if (logger.isDebugEnabled()) {
                    String exMsg = ex.getMessage();
                    if (exMsg != null && !exMsg.contains(parameter.getExecutable().toGenericString())) {
                        logger.debug(formatArgumentError(parameter, exMsg));
                    }
                }
                throw ex;
            }
        }
        return args;
    }
    
    1. 获取之前在HandlerMethod实例中保存的参数数组.
    2. 遍历参数数组,给每一个参数初始化一个参数名称发现器,目的是为了匹配各种的参数声明.
    3. 解析并绑定参数.
    参数解析器
    • org.springframework.web.method.support.HandlerMethodArgumentResolverComposite#resolveArgument
    public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
        NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
    // 首先获取参数解析器,这里获取的逻辑是首先从argumentResolverCache缓存中
    // 获取该MethodParameter匹配的HandlerMethodArgumentResolver
    // 如果为空,遍历初始化定义的26个解析器实例
    // 查找匹配的HandlerMethodArgumentResolver,然后添加至argumentResolver缓存中
    HandlerMethodArgumentResolver resolver = getArgumentResolver(parameter);
    if (resolver == null) {
        throw new IllegalArgumentException("Unsupported parameter type [" +
                parameter.getParameterType().getName() + "]. supportsParameter should be called first.");
    }
    return resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory);
    }
    

    关于参数解析,Spring提供了很多支持,比如支持@RequestParam@PathVariable等,我们今天来看一个默认的解析器-org.springframework.web.method.annotation.AbstractNamedValueMethodArgumentResolver

    • org.springframework.web.method.annotation.AbstractNamedValueMethodArgumentResolver#resolveArgument
    public final Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
            NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
    
        NamedValueInfo namedValueInfo = getNamedValueInfo(parameter);
        MethodParameter nestedParameter = parameter.nestedIfOptional();
        // 解析出参数名
        Object resolvedName = resolveStringValue(namedValueInfo.name);
        if (resolvedName == null) {
            throw new IllegalArgumentException(
                    "Specified name must not resolve to null: [" + namedValueInfo.name + "]");
        }
        // 和请求中的参数名进行对照,获取请求参数对应的string类型的值
        Object arg = resolveName(resolvedName.toString(), nestedParameter, webRequest);
        if (arg == null) {
            if (namedValueInfo.defaultValue != null) {
                arg = resolveStringValue(namedValueInfo.defaultValue);
            }
            else if (namedValueInfo.required && !nestedParameter.isOptional()) {
                handleMissingValue(namedValueInfo.name, nestedParameter, webRequest);
            }
            arg = handleNullValue(namedValueInfo.name, arg, nestedParameter.getNestedParameterType());
        }
        else if ("".equals(arg) && namedValueInfo.defaultValue != null) {
            arg = resolveStringValue(namedValueInfo.defaultValue);
        }
    
        if (binderFactory != null) {
            WebDataBinder binder = binderFactory.createBinder(webRequest, null, namedValueInfo.name);
            try {
                // 参数类型转换
                arg = binder.convertIfNecessary(arg, parameter.getParameterType(), parameter);
            }
            catch (ConversionNotSupportedException ex) {
                throw new MethodArgumentConversionNotSupportedException(arg, ex.getRequiredType(),
                        namedValueInfo.name, parameter, ex.getCause());
            }
            catch (TypeMismatchException ex) {
                throw new MethodArgumentTypeMismatchException(arg, ex.getRequiredType(),
                        namedValueInfo.name, parameter, ex.getCause());
    
            }
        }
    
        handleResolvedValue(arg, namedValueInfo.name, parameter, mavContainer, webRequest);
    
        return arg;
    }
    
    1. 获取参数名称,并解析成String类型.
    2. 根据参数名获取请求中对应的参数. (大致相当于request.getParameterValues(name);)
    3. 按参数声明的类型进行转换.
    ModelAndView
    public class ModelAndView {
    
        /** View instance or view name String. */
        /**
         * 请求视图路径
         */
        @Nullable
        private Object view;
    
        /** Model Map. */
        /**
         * 请求结果集
         */
        @Nullable
        private ModelMap model;
    
        /** Optional HTTP status for the response. */
        @Nullable
        private HttpStatus status;
    
        /** Indicates whether or not this instance has been cleared with a call to {@link #clear()}. */
        private boolean cleared = false;
    }
    

    ModelAndView主要包装view和model,其中,view代表的是请求视图路径,model代表的是请求结果集.

    applyDefaultViewName-处理视图

    如果指定了视图,那么要对返回结果进行处理,比如是JSP请求响应的String,往往需要加上.jsp的后缀.

    applyPostHandle-后置处理

    后置处理拦截器的激活

    processDispatchResult-结果集渲染

    private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
            @Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
            @Nullable Exception exception) throws Exception {
    
        boolean errorView = false;
        // 对异常进行处理
        if (exception != null) {
            if (exception instanceof ModelAndViewDefiningException) {
                logger.debug("ModelAndViewDefiningException encountered", exception);
                mv = ((ModelAndViewDefiningException) exception).getModelAndView();
            }
            else {
                Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
                mv = processHandlerException(request, response, handler, exception);
                errorView = (mv != null);
            }
        }
    
        // Did the handler return a view to render?
        if (mv != null && !mv.wasCleared()) {
            // 视图的渲染
            render(mv, request, response);
            if (errorView) {
                WebUtils.clearErrorRequestAttributes(request);
            }
        }
        else {
            if (logger.isTraceEnabled()) {
                logger.trace("No view rendering, null ModelAndView returned.");
            }
        }
    
        if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
            // Concurrent handling started during a forward
            return;
        }
    
        if (mappedHandler != null) {
            mappedHandler.triggerAfterCompletion(request, response, null);
        }
    }
    
    1. 如果方法执行产生了异常,那么执行异常包装器的渲染逻辑.
    2. 如果返回的ModelAndView为空,那么执行render.

    MVC处理流程

    这里还是贴出最经典的一个答案,答案还是自己总结.

    流程

    摘自《Spring 5核心原理与30个类手写实战_谭勇德》

    相关文章

      网友评论

        本文标题:[Spring MVC]Spring MVC是如何处理请求的

        本文链接:https://www.haomeiwen.com/subject/sdadfrtx.html