图文源码分析Spring MVC请求映射原理、执行流程

简介: 图文源码分析Spring MVC请求映射原理、执行流程

一、Spring MVC执行流程(总结)

请添加图片描述

  1. 客户端的所有请求都会交给前端控制器DispatcherServlet来处理,DispatcherServlet会负责调用系统的其他模块来完成用户请求的处理;
  2. 即用户发送的请求会先从DispatcherServletdoService()方法开始;在该方法中会先将webApplicationContext、localeResolver、themeResolver等对象添加到request请求的attribute属性中,接着调用doDispatch()方法;
  3. 进入到doDispatch()方法中:

    1. 首先检查请求是否为文件的上传/下载请求(校验的规则是:是否是post并且contenttType是否以multipart为前缀),如果是则将请求包装成MultipartHttpServletRequest
    2. 其次调用getHandler()方法从五个HandlerMapping中找到相应的HandlerMapping对象(以普通HTTP请求为例,HandlerMapping为requestMappingHandlerMapping),进而获取到该Handler对应的处理链HandlerExecutionChain对象
    3. 其实在获取HandlerExecutionChain时,其内部也获取到了Spring自带的以及我们自定义的MVC拦截器;
    4. 然后通过上面获取到的HandlerExecutionChain对象,进而从四个HandlerAdapter中获取相应的HandlerAdapter处理器适配器(HandlerAdapter是一个适配器,它用统一的接口对各种Handler中的方法进行调用)。
    5. 执行处理链HandlerExecutionChain中全部拦截器的preHandle()方法,如果返回FALSE,则执行处理链中所有拦截器的afterCompletion()方法并立即返回。
    6. 接着调用handlerAdapter对象的handle()方法来执行Controller中的方法;

      1> 其中会获取26个参数解析器HandlerMethodArgumentResolver,15个返回值处理器HandlerMethodReturnValueHandler

      2> 最后通过反射,打开Controller相应方法的访问权限,进而调用相应的方法

    7. HandlerAdapter执行完,返回一个ModelAndView给DispatcherServlet;并执行拦截器的postHandle()方法;如果出现异常,则有HandlerExceptionHandler处理异常,得到新的ModelAndView对象;
    8. 由于ModelAndView的视图是逻辑视图,DispatcherServlet还要借助ViewResolver完成从逻辑视图到真实视图对象的解析工作
    9. 当得到真正的View视图后,DispatcherServlet会利用这个View视图对象对模型数据ModelAndView进行渲染;
    10. 调用处理链中所有拦截器的afterCompletion()方法
    11. 客户端得到响应,可能是一个普通的HTML页面,也可以是XML或JSON字符串,还可以是一张图片或者一个PDF文件。

注:在整个SpringMVC的执行流程中,大量使用了模板方法,比如:HandlerAdapter#handle()方法(具体的handleInternal()逻辑由子类实现),FrameServlet#processRequest()方法(具体的doService()逻辑由子类实现)

以GET请求为例:

@RestController
public class TestController {
    @GetMapping("/hello")
    public String hello() {
        return "hello";
    }
}

在这里插入图片描述

二、源码分析请求映射原理/执行流程

HTTP请求的入口为DispatcherServlet,DispatcherServlet继承自FrameworkServlet,在FrameworkServlet的doGet()方法便是GET请求的入口。

在这里插入图片描述

无论是doGet()、doPost()、doPut()、doDelete()都会进入到processRequest(request, response)方法处理请求。

protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException {

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

    // 构建语言环境
    LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
    LocaleContext localeContext = buildLocaleContext(request);

    // 从请求中获取参数
    RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
    // 从servlet中构建参数
    ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);

    // 构建web异步管理器
    WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
    asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());

    // 初始化上下文信息
    initContextHolders(request, localeContext, requestAttributes);

    try {
        // 决定一个请求过来应该找到哪个Controller
        doService(request, response);
    }
    catch (ServletException | IOException ex) {
        failureCause = ex;
        throw ex;
    }
    catch (Throwable ex) {
        failureCause = ex;
        throw new NestedServletException("Request processing failed", ex);
    }

    finally {
        resetContextHolders(request, previousLocaleContext, previousAttributes);
        if (requestAttributes != null) {
            requestAttributes.requestCompleted();
        }
        logResult(request, response, failureCause, asyncManager);
        publishRequestHandledEvent(request, response, startTime, failureCause);
    }
}

由于FrameworkServletdoService()是一个抽象方法(这样看processRequest()也是用了模板方法设计模式),我们去DispatcherServlet中看具体的实现

1)doService()

@Override
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
    logRequest(request);

    // request请求添加属性
    ......

    // 将请求的跳转信息保存起来(Controller的return是return到一个接口)
    if (this.flashMapManager != null) {
        FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);
        if (inputFlashMap != null) {
            request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));
        }
        request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
        request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);
    }

    try {
        /**
         * 真正分发请求的地方
         */
        doDispatch(request, response);
    }
    finally {
        if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
            // Restore the original attribute snapshot, in case of an include.
            if (attributesSnapshot != null) {
                restoreAttributesAfterInclude(request, attributesSnapshot);
            }
        }
    }
}

接着进入到doDispatch(request, response)方法,看它是怎么分派的?

2)doDispatch()

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
    HttpServletRequest processedRequest = request;
    HandlerExecutionChain mappedHandler = null;
    boolean multipartRequestParsed = false;

    // web异步处理管理类
    WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

    try {
        // 定义最后返回的ModelAndView视图
        ModelAndView mv = null;
        Exception dispatchException = null;

        try {
            // Case1、检查请求是否为上传/下载请求
            processedRequest = checkMultipart(request);
            multipartRequestParsed = (processedRequest != request);

            // Case2、从handlerMappings中获取请求对应的处理器执行链HandlerExecutionChain
            mappedHandler = getHandler(processedRequest);
            if (mappedHandler == null) {
                noHandlerFound(processedRequest, response);
                return;
            }

            // Case3、 从handlerAdapters中获取请求的适配器`HandlerAdapter`
            HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

            // Process last-modified header, if supported by the handler.
            String method = request.getMethod();
            boolean isGet = "GET".equals(method);
            if (isGet || "HEAD".equals(method)) {
                long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
                if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
                    return;
                }
            }

            // 执行HandlerExecutionHandler处理链中拦截器的preHandle()方法,如果返回false,则执行afterCompletion()方法并立即返回
            if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                return;
            }

            // Case1--Case3都为准备阶段
            // Case4、真正执行请求适配器HandlerAdapter
            mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

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

            applyDefaultViewName(processedRequest, mv);
            // 执行HandlerExecutionHandler处理链中拦截器的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);
            }
        }
    }
}

Case1:判断是否为上传/下载请求:

以普通的GET请求为例,判断出不是上传/下载请求;
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dLzyOmjj-1647330959311)(.\picture\SpringMVC\SpringMVC请求映射流程2.png)]

Case2: 通过getHandler()方法获取请求对应的处理器执行链HandlerExecutionChain;

3)getHandler()

@Nullable
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    // 在Spring初始化的时候会加载所有的handlerMappings
    if (this.handlerMappings != null) {
        for (HandlerMapping mapping : this.handlerMappings) {
            // 获取请求对应的HandlerExecutionChain
            HandlerExecutionChain handler = mapping.getHandler(request);
            if (handler != null) {
                return handler;
            }
        }
    }
    return null;
}

1> 获取所有HandlerMapping类型的Bean:

Spring启动时会加载五个HandlerMapping类型的Bean到IOC容器中,分别为:

  1. requestMappingHandlerMapping,请求处理器
  2. beanNameHandlerMapping
  3. routerFunctionMapping
  4. resourceHandlerMapping
  5. welcomePageHandlerMapping

其中针对HTTP GET、POST普通请求而言,我们主要看requestMappingHandlerMapping,其中包含所有注册的可以处理请求、以及请求和相应类/方法的映射Mapping。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eikU5Zke-1647330959311)(.\picture\SpringMVC\SpringMVC请求映射流程3.png)]

2> 以普通的GET、POST请求为例,通过requestMappingHandlerMapping获取请求对应的HandlerExecutionChain

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nAjLp04Q-1647330959311)(.\picture\SpringMVC\SpringMVC请求映射流程4.png)]

getHandler()方法是如何获取到具体的HandlerExecutionChain的?

进入到AbstractHandlerMapping# getHandler()方法看具体的获取HandlerExecutionChain逻辑;

/**
 * 在AbstractHandlerMapping类中
 */
@Override
@Nullable
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    // 1、获取请求对应的HandlerMethod
    Object handler = getHandlerInternal(request);
    if (handler == null) {
        handler = getDefaultHandler();
    }
    if (handler == null) {
        return null;
    }
    // Bean name or resolved handler?
    if (handler instanceof String) {
        String handlerName = (String) handler;
        handler = obtainApplicationContext().getBean(handlerName);
    }

    // 2、获取请求对应的HandlerExecutionChain(默认添加两个拦截器)
    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 (hasCorsConfigurationSource(handler) || CorsUtils.isPreFlightRequest(request)) {
        CorsConfiguration config = (this.corsConfigurationSource != null ? this.corsConfigurationSource.getCorsConfiguration(request) : null);
        CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
        config = (config != null ? config.combine(handlerConfig) : handlerConfig);
        executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
    }

    return executionChain;
}

1> 获取请求对应的HandlerMethod:

/**
 * AbstractHandlerMethodMapping#getHandlerInternal()方法
 */
@Override
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
    // 从请求中获取请求的路径
    String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
    request.setAttribute(LOOKUP_PATH, lookupPath);
    this.mappingRegistry.acquireReadLock();
    try {
        // 根据请求路径查找相应的HandlerMethod
        HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
        return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
    }
    finally {
        this.mappingRegistry.releaseReadLock();
    }
}

先从请求中获取请求的路径,然后根据请求路径和请求通过lookupHandlerMethod()方法获取HandlerMathod

@Nullable
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
    List<Match> matches = new ArrayList<>();
    // 从mappingRegistry的urlLookup中根据urlPath获取匹配的请求路径
    List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
    if (directPathMatches != null) {
        // 找到匹配的请求路径,则添加到matches集合中
        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()) {
        Match bestMatch = matches.get(0);
        if (matches.size() > 1) {
            Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
            matches.sort(comparator);
            bestMatch = matches.get(0);
            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);
    }
}

phase1:从mappingRegistry的urlLookup中根据urlPath获取匹配的请求路径(this.mappingRegistry.getMappingsByUrl(lookupPath)):

public List<T> getMappingsByUrl(String urlPath) {
    return this.urlLookup.get(urlPath);
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-m3GrVJqD-1647330959311)(.\picture\SpringMVC\SpringMVC请求映射流程5.png)]

phase2:如果获取到多个HandlerMethod,从所有匹配的HandlerMethod中找出一个最匹配的(bestMatch)

2> 获取请求对应的执行链HandlerExecutionChain(默认添加两个拦截器):

也就是添加一些拦截器对请求执行过滤、拦截。

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);
    for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
        if (interceptor instanceof MappedInterceptor) {
            MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
            if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
                chain.addInterceptor(mappedInterceptor.getInterceptor());
            }
        }
        else {
            chain.addInterceptor(interceptor);
        }
    }
    return chain;
}

其中默认添加两个拦截器:

  1. ConversionServiceExposingInterceptor
  2. ResourceUrlProviderExposingInterceptor

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-K9p6VfBD-1647330959312)(.\picture\SpringMVC\SpringMVC请求映射流程6.png)]

Case3: 获取完请求对应的HandlerExecutionChain之后,通过getHandlerAdapter()进一步获取请求的适配器HandlerAdapter

4)getHandlerAdapter()

对于HTTP请求而言,HandlerAdapter就是HttpRequestHandlerAdapter

protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
    if (this.handlerAdapters != null) {
        // 1、获取所有HandlerAdapter类型的bean
        for (HandlerAdapter adapter : this.handlerAdapters) {
            // 找到具体HandlerAdapter
            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");
}

1> 获取所有HandlerAdapter类型的Bean:

Spring启动时会加载四个HandlerAdapter类型的Bean到IOC容器中,分别为:

  1. RequestMappingHandlerAdapter,HTTP请求的HandlerAdapter
  2. HandlerFunctionAdapter
  3. HttpRequestHandlerAdapter
  4. SimpleControllerHandlerAdapter

2> 找到符合相应HandlerMethod的HandlerAdapter:

HandlerAdapter#supports()方法本质上就是一个instanceof类型判断,以HttpRequestHandlerAdapter为例:

public class HttpRequestHandlerAdapter implements HandlerAdapter {

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-J3kSho3L-1647330959312)(.\picture\SpringMVC\SpringMVC请求映射流程7.png)]

Case4: 通过HandlerAdapter#handle()方法开始真正执行相应的HandlerAdapter;

5)HandlerAdapter#handle()

进入到AbstractHandlerMethodAdapter#handle()方法

@Override
@Nullable
public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
    throws Exception {

    return handleInternal(request, response, (HandlerMethod) handler);
}

这里AbstractHandlerMethodAdapter#handleInternal()又是一个抽象方法,即其上层handle()方法是一个模板方法

@Nullable
protected abstract ModelAndView handleInternal(HttpServletRequest request,
                                               HttpServletResponse response, HandlerMethod handlerMethod) throws Exception;

对于HTTP请求,会进入到AbstractHandlerMethodAdapter的子类RequestHandlerMethodAdapter#handlerInternal()方法:

@Override
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 {
        // 真正执行适配器adapter的方法
        // 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;
}

进入到invokeHandlerMethod()方法,看看Spring MVC是如何执行适配器HandlerAdapter的方法的?

6)RequestHandlerMethodAdapter#invokeHandlerMethod()

@Nullable
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);

        ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
        // 解析请求的参数,参数解析器HandlerMethodArgumentResolverComposite有26个
        if (this.argumentResolvers != null) {
            invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
        }
        // 返回值处理器
        if (this.returnValueHandlers != null) {
            invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
        }
        // 一堆赋值操作
        .....

        // 调用方法,然后执行
        invocableMethod.invokeAndHandle(webRequest, mavContainer);
        if (asyncManager.isConcurrentHandlingStarted()) {
            return null;
        }

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

phase1:获取参数解析器HandlerMethodArgumentResolver;

参数解析器HandlerMethodArgumentResolver

  • 包含两个方法,分别为
  • supportsParameter() ---> 判断响应方法参数parameter是否可以被当前HandlerMethodArgumentResolver解析?
  • resolveArgument() ---> 进行方法参数解析
public interface HandlerMethodArgumentResolver {
    // 判断parameter是不是xxArgumentResolver可以解析的
    boolean supportsParameter(MethodParameter parameter);

    @Nullable
    // 方法参数解析的主要逻辑
    @Nullable
    Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
                           NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception;
}
  • 方法参数解析器argumentResolvers一共有26个:

在这里插入图片描述
在这里插入图片描述

0 = {RequestParamMethodArgumentResolver@6374}
1 = {RequestParamMapMethodArgumentResolver@6375}
2 = {PathVariableMethodArgumentResolver@6376}
3 = {PathVariableMapMethodArgumentResolver@6377}
4 = {MatrixVariableMethodArgumentResolver@6378}
5 = {MatrixVariableMapMethodArgumentResolver@6379}
6 = {ServletModelAttributeMethodProcessor@6380}
7 = {RequestResponseBodyMethodProcessor@6381}
8 = {RequestPartMethodArgumentResolver@6382}
9 = {RequestHeaderMethodArgumentResolver@6383}
10 = {RequestHeaderMapMethodArgumentResolver@6384}
11 = {ServletCookieValueMethodArgumentResolver@6385}
12 = {ExpressionValueMethodArgumentResolver@6386}
13 = {SessionAttributeMethodArgumentResolver@6387}
14 = {RequestAttributeMethodArgumentResolver@6388}
15 = {ServletRequestMethodArgumentResolver@6389}
16 = {ServletResponseMethodArgumentResolver@6390}
17 = {HttpEntityMethodProcessor@6391}
18 = {RedirectAttributesMethodArgumentResolver@6392}
19 = {ModelMethodProcessor@6393}
20 = {MapMethodProcessor@6394}
21 = {ErrorsMethodArgumentResolver@6395}
22 = {SessionStatusMethodArgumentResolver@6396}
23 = {UriComponentsBuilderMethodArgumentResolver@6397}
24 = {RequestParamMethodArgumentResolver@6398}
25 = {ServletModelAttributeMethodProcessor@6399}

phase2:获取返回值/结果处理器HandlerMethodReturnValueHandler;

返回值/结果处理器HandlerMethodReturnValueHandler

  • 包含两个方法,分别为
  • supportsReturnType() ---> 判断响应方法放回值是否可以被当前HandlerMethodReturnValueHandler处理?
  • handleReturnValue() ---> 进行返回值处理
public interface HandlerMethodReturnValueHandler {
    //xxMethodReturnValueHandler是否能处理这个returnType
    boolean supportsReturnType(MethodParameter returnType);

    // 处理返回值
    void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
                           ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception;
  • 返回值/结果处理器一共有15个:

在这里插入图片描述
在这里插入图片描述

0 = {ModelAndViewMethodReturnValueHandler@6417}
1 = {ModelMethodProcessor@6418}
2 = {ViewMethodReturnValueHandler@6419}
3 = {ResponseBodyEmitterReturnValueHandler@6420}
4 = {StreamingResponseBodyReturnValueHandler@6421}
5 = {HttpEntityMethodProcessor@6422}
6 = {HttpHeadersReturnValueHandler@6423}
7 = {CallableMethodReturnValueHandler@6424}
8 = {DeferredResultMethodReturnValueHandler@6425}
9 = {AsyncTaskMethodReturnValueHandler@6426}
10 = {ModelAttributeMethodProcessor@6427}
11 = {RequestResponseBodyMethodProcessor@6428}
12 = {ViewNameMethodReturnValueHandler@6429}
13 = {MapMethodProcessor@6430}

phase3:执行方法;

进入到ServletInvocableHandlerMethod#invokeAndHandle(webRequest, mavContainer)方法;

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

    // 真正执行请求的地方
    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 {
        this.returnValueHandlers.handleReturnValue(
            returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
    }
    catch (Exception ex) {
        if (logger.isTraceEnabled()) {
            logger.trace(formatErrorForReturnValue(returnValue), ex);
        }
        throw ex;
    }
}

再进入到InvocableHandlerMethod#invokeForRequest()看是如何处理请求的?

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

    // 获取方法的入参
    Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
    if (logger.isTraceEnabled()) {
        logger.trace("Arguments: " + Arrays.toString(args));
    }
    // 调用真正的Controller
    return doInvoke(args);
}

再看doInvoke()方法如何执行?

  • 通过反射、打开Controller相应方法的访问权限,进而调用相应的方法。
@Nullable
protected Object doInvoke(Object... args) throws Exception {
    // 获得被桥接的⽅法(如果是桥接方法,则返回被桥接的方法,否则直接返回 getMethod()),然后打开访问权限
    ReflectionUtils.makeAccessible(getBridgedMethod());
    try {
        //  通过反射,调⽤Controller中相应的⽅法
        return getBridgedMethod().invoke(getBean(), args);
    }
    catch (IllegalArgumentException ex) {
        ......
    }
}

最后再回到DispatcherServlet#doDispatch()方法中,看其调用processDispatchResult()方法如何处理返回结果?

processDispatchResult()

这里会进行异常的处理、视图的渲染、以及HandlerAdapter中所有拦截器的afterCompletion()方法。

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);
        }
    }

    /** 处理程序是否返回要渲染的视图? */
    if (mv != null && !mv.wasCleared()) {
        /** 进行视图渲染 */
        // eg3:
        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;
    }

    // 执行HandlerExecutionChain中拦截器的afterCompletion()方法
    if (mappedHandler != null) {
        mappedHandler.triggerAfterCompletion(request, response, null);
    }
}
相关文章
|
1月前
|
缓存 前端开发 Java
Spring MVC 面试题及答案整理,最新面试题
Spring MVC 面试题及答案整理,最新面试题
90 0
|
1月前
|
XML Java 开发者
Spring Boot中的bean注入方式和原理
Spring Boot中的bean注入方式和原理
52 0
|
26天前
|
安全 Java 数据安全/隐私保护
【深入浅出Spring原理及实战】「EL表达式开发系列」深入解析SpringEL表达式理论详解与实际应用
【深入浅出Spring原理及实战】「EL表达式开发系列」深入解析SpringEL表达式理论详解与实际应用
57 1
|
26天前
|
存储 XML 缓存
【深入浅出Spring原理及实战】「缓存Cache开发系列」带你深入分析Spring所提供的缓存Cache功能的开发实战指南(一)
【深入浅出Spring原理及实战】「缓存Cache开发系列」带你深入分析Spring所提供的缓存Cache功能的开发实战指南
60 0
|
12天前
|
数据采集 前端开发 Java
数据塑造:Spring MVC中@ModelAttribute的高级数据预处理技巧
数据塑造:Spring MVC中@ModelAttribute的高级数据预处理技巧
23 3
|
12天前
|
存储 前端开发 Java
会话锦囊:揭示Spring MVC如何巧妙使用@SessionAttributes
会话锦囊:揭示Spring MVC如何巧妙使用@SessionAttributes
14 1
|
12天前
|
前端开发 Java Spring
数据之桥:深入Spring MVC中传递数据给视图的实用指南
数据之桥:深入Spring MVC中传递数据给视图的实用指南
29 3
|
21天前
|
前端开发 安全 Java
使用Java Web框架:Spring MVC的全面指南
【4月更文挑战第3天】Spring MVC是Spring框架的一部分,用于构建高效、模块化的Web应用。它基于MVC模式,支持多种视图技术。核心概念包括DispatcherServlet(前端控制器)、HandlerMapping(请求映射)、Controller(处理请求)、ViewResolver(视图解析)和ModelAndView(模型和视图容器)。开发流程涉及配置DispatcherServlet、定义Controller、创建View、处理数据、绑定模型和异常处理。
使用Java Web框架:Spring MVC的全面指南
|
27天前
|
XML 缓存 Java
天天用 Spring,bean 实例化原理你懂吗
天天用 Spring,bean 实例化原理你懂吗
17 0
|
1月前
ssm(Spring+Spring mvc+mybatis)Dao层实现类——DeptDaoImpl
ssm(Spring+Spring mvc+mybatis)Dao层实现类——DeptDaoImpl
12 0