Spring源码-SpringMVC-DispatcherServlet#doDispatch

总结摘要
SpringMVC Web DispatcherServlet#doDispatch Method Execution Process

请求入口

1
2
3
4
5
6
7
-> Tomcat 网络连接
-> StandardEngineValve
-> StandardHostValve
-> StandardContextValve
-> StandardContextValve
-> ApplicationFilterChain
-> HttpServlet

Servlet 入口

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
// 请求流程
// javax.servlet.http.HttpServlet#service(javax.servlet.ServletRequest, javax.servlet.ServletResponse)
-> org.springframework.web.servlet.FrameworkServlet#service
    -> 如果是 PATCH 方法或空方法if (httpMethod == HttpMethod.PATCH || httpMethod == null) 
        -> 详情参加 POST 方法org.springframework.web.servlet.FrameworkServlet#processRequest
    -> javax.servlet.http.HttpServlet#service(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
        -> 根据方法类型路由到不同的方法
            -> GETlastModified 参数相关适配
            -> POSTorg.springframework.web.servlet.FrameworkServlet#doPost
                -> org.springframework.web.servlet.FrameworkServlet#processRequest
                    -> LocaleContextRequestAttributes 等处理
                    -> org.springframework.web.servlet.DispatcherServlet#doService
                        -> 详情参加分支 DispatcherServlet#doDispatchorg.springframework.web.servlet.DispatcherServlet#doDispatch
            -> PUT
            -> OPTION
            -> 其它方法略

请求分发

分支 DispatcherServlet#doDispatch

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
分支 DispatcherServlet#doDispatch
org.springframework.web.servlet.DispatcherServlet#doDispatch
-> WebAsyncManager 预处理获取或创建 WebAsyncManagerorg.springframework.web.context.request.async.WebAsyncUtils#getAsyncManager(javax.servlet.ServletRequest)
    -> 场景一获取servletRequest.getAttribute(WEB_ASYNC_MANAGER_ATTRIBUTE)
    -> 场景二创建new WebAsyncManager()存储到属性中
    -> 当前获取成功

-> multipart 相关处理如果是 multipart 请求则将 request 封装为 StandardMultipartHttpServletRequest  DefaultMultipartHttpServletRequestorg.springframework.web.servlet.DispatcherServlet#checkMultipart
    -> this.multipartResolver 的默认实现类是 org.springframework.web.multipart.support.StandardServletMultipartResolver另外一种实现是 org.springframework.web.multipart.commons.CommonsMultipartResolver
    -> 校验 Multipartorg.springframework.web.multipart.support.StandardServletMultipartResolver#isMultipart
        -> 默认是宽松校验方式
        -> 宽松校验方式校验 ContentType  `multipart/` 开头
        -> 严格校验方式严格遵守 Servlet 规范校验 ContentType  `multipart/form-data`。
    -> if (WebUtils.getNativeRequest(request, MultipartHttpServletRequest.class)) 如果 request instanceof MultipartHttpServletRequest则返回
    -> else  request 封装为 MultipartHttpServletRequest 的实现类 StandardMultipartHttpServletRequest默认 DefaultMultipartHttpServletRequest
        -> 封装 requestorg.springframework.web.multipart.MultipartResolver#resolveMultipart

->  this.handlerMappings 查找适用的 Handler返回第一个匹配的 HandlerExecutionChainorg.springframework.web.servlet.DispatcherServlet#getHandler
    -> for-each this.handlerMappings
        -> 默认有 6 有序排列分别如下其中第一个是关键实现 org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping
            -> RequestMappingHandlerMapping
            -> WelcomePageHandlerMapping
            -> BeanNameUrlHandlerMapping
            -> RouterFunctionMapping
            -> WelcomePageNotAcceptableHandlerMapping
            -> SimpleUrlHandlerMapping
        -> 调用 mapping.getHandler(request)如果找到了适用的 HandlerExecutionChain退出 for-each即返回第一个
        ->  RequestMappingHandlerMapping 为例分析详情参见分支 RequestMappingHandlerMapping#getHandler》。

-> 如果未找到则抛出异常org.springframework.web.servlet.DispatcherServlet#noHandlerFound

->  this.handlerAdapters 查找并返回第一个匹配的 HandlerAdapterorg.springframework.web.servlet.DispatcherServlet#getHandlerAdapter
    -> for-each this.handlerAdapters
        -> 当前有 4 默认始终返回 RequestMappingHandlerAdapter
        -> 如果 org.springframework.web.servlet.HandlerAdapter#supports  true则退出 for-each返回第一个匹配的 HandlerAdapter
        ->  RequestMappingHandlerAdapter 为例分析
            -> org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter#supports
                -> 要求 handle  HandlerMethod 的实例且 supportsInternal 方法返回 true
                -> RequestMappingHandlerAdapter#supportsInternal 始终返回 true因此几乎所有请求都会使用 RequestMappingHandlerAdapter
                -> 例外场景CORS 预检查请求 handler PreFlightHandler 不是 HandlerMethod 实例而是 HttpRequestHandler 实例
        -> 如果未找到匹配的则抛出 ServletException 异常

-> 如果请求方法是 GET  HEAD分析 lastModified 判断是否可以直接返回请求

-> 拦截器处理执行上一步筛选出的 interceptororg.springframework.web.servlet.HandlerExecutionChain#applyPreHandle
    -> for-each interceptorList
        -> 调用 preHandle 方法org.springframework.web.servlet.HandlerInterceptor#preHandle
        -> 如果有 preHandle 方法返回 false则调用 org.springframework.web.servlet.HandlerExecutionChain#triggerAfterCompletion然后返回 false
    -> 默认返回 true
-> 如果 applyPreHandle 返回 false则退出方法

-> 执行 handle 方法org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter#handle
    -> 执行 handle 方法 RequestMappingHandlerAdapter详情参见RequestMappingHandlerAdapter#handleInternal》。

-> 如果满足 if (asyncManager.isConcurrentHandlingStarted())则返回方法
-> 视图名称处理org.springframework.web.servlet.DispatcherServlet#applyDefaultViewName
    -> 默认视图org.springframework.web.servlet.DispatcherServlet#getDefaultViewName
        -> 调用默认视图处理器org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator#getViewName
-> 拦截器处理org.springframework.web.servlet.HandlerExecutionChain#applyPostHandle
    -> for-each interceptorList
        -> 调用 postHandle 方法org.springframework.web.servlet.HandlerInterceptor#postHandle    

-> 处理请求结果org.springframework.web.servlet.DispatcherServlet#processDispatchResult
    -> 异常处理详情参见其它篇章org.springframework.web.servlet.DispatcherServlet#processHandlerException
    -> 拦截器 AfterCompletion 方法org.springframework.web.servlet.HandlerExecutionChain#triggerAfterCompletion
        -> for-each interceptorList, org.springframework.web.servlet.HandlerInterceptor#afterCompletion

-> 异步请求相关处理详情略asyncManager.isConcurrentHandlingStarted()

-> 文件上传相关处理详情略if (multipartRequestParsed)org.springframework.web.servlet.DispatcherServlet#cleanupMultipart

分支

分支 RequestMappingHandlerMapping#getHandler

入口方法

org.springframework.web.servlet.DispatcherServlet#getHandler

org.springframework.web.servlet.handler.AbstractHandlerMapping#getHandler

主流程

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
// org.springframework.web.servlet.handler.AbstractHandlerMapping#getHandler
-> org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping#getHandlerInternal
    -> org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#getHandlerInternal
        -> org.springframework.web.servlet.handler.AbstractHandlerMapping#initLookupPath
            -> if (usesPathPatterns()) 当前满足条件
                -> 判断逻辑是判断 this.patternParser 是否存在 org.springframework.web.servlet.handler.AbstractHandlerMapping#patternParser
                    -> 当前使用 org.springframework.web.util.pattern.PathPatternParser
                -> 查找已解析并缓存在属性中的 RequestPathorg.springframework.web.util.ServletRequestPathUtils#getParsedRequestPath
                -> 删除 path 中的分号及之后的内容包含 JsessionIdorg.springframework.web.util.UrlPathHelper#removeSemicolonContent
            -> else
                -> 使用 this.urlPathHelper 解析 request pathorg.springframework.web.util.UrlPathHelper#resolveAndCacheLookupPath
                    -> org.springframework.web.util.UrlPathHelper#getLookupPathForRequest(javax.servlet.http.HttpServletRequest) 详情略
        -> this.mappingRegistry 锁处理并发控制
        -> org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#lookupHandlerMethod
            -> 根据 path 筛选符合条件的处理器常用实现类是 RequestMappingInfo此处为宽松匹配org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.MappingRegistry#getMappingsByDirectPath
                -> 调用 this.pathLookup.get(urlPath); 
                    -> 变量定义 org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.MappingRegistry#pathLookup
                    -> 变量定义 private final MultiValueMap<String, T> pathLookup = new LinkedMultiValueMap<>();
            -> 严格匹配org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#addMatchingMappings
                -> for-each mappings, 即上一步宽松匹配的结果
                    -> 严格匹配org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping#getMatchingMapping
                        -> 调用 org.springframework.web.servlet.mvc.method.RequestMappingInfo#getMatchingCondition
                            -> 严格匹配 Request 的各种属性是否满足条件如果不满足则返回 null如果满足则返回重新封装的 RequestMappingInfo 对象
                            -> 校验的属性包括 http methodparamsheadersconsumesproduces 
                    -> 封装为包含 HandlerMethod 和关联 mapping  Matchorg.springframework.web.servlet.handler.AbstractHandlerMethodMapping.Match
            -> 如果未找到则从全量候选值中进行严格匹配筛选核实的 mapping
            -> 如果匹配多个则排序找到最优的选择org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.MatchComparator#MatchComparator
            -> 暴露 URL 中涉及的变量org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping#handleMatch
                ->  Request 缓存属性值为 lookupPathorg.springframework.web.servlet.handler.AbstractHandlerMethodMapping#handleMatch
                -> matrix variables 处理org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping#extractMatchDetails(org.springframework.web.servlet.mvc.condition.PathPatternsRequestCondition, java.lang.String, javax.servlet.http.HttpServletRequest)
                -> mediaTypes 处理
            -> 返回 HandlerMethod
        -> org.springframework.web.method.HandlerMethod#createWithResolvedBean
            ->  beanFactory 中获取 Controller bean
            -> 重新封装为 HandlerMethodnew HandlerMethod
        -> this.mappingRegistry 锁处理并发控制

-> 如果未找到合适的 handler则使用 this.defaultHandler默认为 null
-> 确认 URL path 属性已缓存org.springframework.web.util.ServletRequestPathUtils#hasCachedPath

-> org.springframework.web.servlet.handler.AbstractHandlerMapping#getHandlerExecutionChain
    -> for-each this.adaptedInterceptors
        -> 当前有 4 其中 3 个是默认的均非 MappedInterceptor),有序排列分别是
            -> MappedInterceptor内部是自定义的 TraceIdInterceptor implements HandlerInterceptor 的封装体关联定义为 registry.addInterceptor(new TraceIdInterceptor()).addPathPatterns("/**");
            -> WebRequestHandlerInterceptorAdapter内部是 org.springframework.orm.jpa.support.OpenEntityManagerInViewInterceptor JPA 有关
            -> ConversionServiceExposingInterceptor主要适用于 JSP 标签具体是将 ConversionService 添加到 request 的属性中
            -> ResourceUrlProviderExposingInterceptor ResourceUrlProvider 配置在属性中                          
        -> if (interceptor instanceof MappedInterceptor) 则进一步判断是否匹配如果不匹配则忽略
            -> 如果 if (mappedInterceptor.matches(request))  true interceptor 则追加到 HandlerExecutionChain
                -> chain.addInterceptor(mappedInterceptor.getInterceptor());
        -> else
            ->  interceptor 追加到 HandlerExecutionChain

-> Cors 相关处理
    -> 判断请求是否涉及 CORS 配置org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#hasCorsConfigurationSource
        -> org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.MappingRegistry#getCorsConfiguration
            -> 使用缓存 org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.MappingRegistry#corsLookup
    -> 判断是否是 CORS 预检查请求方法是 OPTIONS且包含相关请求属性org.springframework.web.cors.CorsUtils#isPreFlightRequest
    -> if  CORS 预检查请求 new PreFlightHandler 并配置 interceptors 后作为 HandlerExecutionChain 返回
    -> else  new CorsInterceptor 添加到 interceptors 并作为第一个校验 ORIGIN 等等

包含路径参数的 url,例如 /explore/hello//hello/{name}/morning不会被缓存到 org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.MappingRegistry#pathLookup中。

debug 验证

this.mappingRegistry.getMappingsByDirectPath("/explore/hello/hello/user1/morning") = null

1
2
3
4
@GetMapping("/hello/{name}/morning")
public Map<String, String> hello2(@PathVariable(value = "name") @Length(min = 2) String name) {
    return Collections.singletonMap("body", "Hello, " + name + " , morning");
}

客户端请求可能会精确匹配到多个@RequestMapping的场景构造。

包含通配符的 URL 的优先级更低。

1
2
3
4
5
@GetMapping("/morning/{name}")
public Map<String, String> morning1(@PathVariable(value = "name") @Length(min = 2) String name);

@GetMapping("/morning/**")
public Map<String, String> morning2();

分支 RequestMappingHandlerAdapter#handleInternal

入口方法

org.springframework.web.servlet.DispatcherServlet#doDispatch

org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter#handle

org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#handleInternal

主流程

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
-> 预检查无实际作用org.springframework.web.servlet.support.WebContentGenerator#checkRequest
-> if (this.synchronizeOnSession) 相关 session 处理
-> 执行 handle 方法org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#invokeHandlerMethod
    ->  request  response 封装为 ServletWebRequest new ServletWebRequest

    -> 获取 WebDataBinderFactoryorg.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#getDataBinderFactory
        -> 根据 Controller  class 从缓存 this.initBinderCache 中获取第一次请求为空org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#initBinderCache
        -> 如果缓存中未找到则从 Controller  class 中筛选注解 @InitBinder 修饰的方法并存储在缓存
        -> 遍历 initBinderAdviceCache
            -> 变量位置 org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#initBinderAdviceCache
            -> 变量定义 private final Map<ControllerAdviceBean, Set<Method>> initBinderAdviceCache = new LinkedHashMap<>();
            -> 如果 org.springframework.web.method.ControllerAdviceBean#isApplicableToBeanType 满足条件
                ->  beanFactory 中获取 controller bean
                    -> for-each methodSet initBinderAdviceCache  value
                        ->  bean  method 封装为 InvocableHandlerMethodorg.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#createInitBinderMethod
                            -> 配置属性 HandlerMethodArgumentResolversDataBinderFactoryParameterNameDiscoverer
                        -> 并临时缓存到方法变量中
            -> for-each methods即从 this.initBinderCache  value
                -> 参考上文详情略org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#createInitBinderMethod
                -> 并临时缓存到方法变量中
            -> 创建 InitBinderDataBinderFactoryorg.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#createDataBinderFactory
                ->  binderMethods  org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#webBindingInitializer 封装为 ServletRequestDataBinderFactorynew ServletRequestDataBinderFactory
                -> 此处的 this.webBindingInitializer 实例是 ConfigurableWebBindingInitializer其中的 validator  conversionService 属性不为空 propertyEditorRegistrars 属性为空其它属性是默认值或为 null
     
    -> 获取 ModelFactoryorg.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#getModelFactory
        ->  controller class 作为 key 获取或生成 SessionAttributesHandler其支持解析 @SessionAttributes 注解定义的属性org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#getSessionAttributesHandler
            -> 默认 this.sessionAttributeStore 的实例是 org.springframework.web.bind.support.DefaultSessionAttributeStore
        ->  controller class 作为 key  this.modelAttributeCache 获取 method
        -> 如果上一步缓存为空则筛选并解析 controller class 中同时由 @RequestMapping 注解和 @ModelAttribute 注解修饰的方法并存储到缓存
        -> for-each modelAttributeAdviceCache
            -> 变量定义 org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#modelAttributeAdviceCache
            -> 变量定义 private final Map<ControllerAdviceBean, Set<Method>> modelAttributeAdviceCache = new LinkedHashMap<>();
            -> 如果 isApplicableToBeanType 满足条件则创建 ModelAttributeMethod
                -> 判断逻辑org.springframework.web.method.ControllerAdviceBean#isApplicableToBeanType 
                    -> 判断逻辑org.springframework.web.method.HandlerTypePredicate#test
                -> for-each methodSet modelAttributeAdviceCache  value
                    -> 封装为 InvocableHandlerMethodorg.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#createModelAttributeMethod
                        -> 配置属性 HandlerMethodArgumentResolversParameterNameDiscovererDataBinderFactory
        -> for-each methods modelAttributeCache  value
            -> 封装为 InvocableHandlerMethod详情略org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#createModelAttributeMethod
        ->  ModelAttributeSessionAttribute  WebDataBinderFactory 封装为 ModelFactorynew ModelFactory
    
    -> 获取 ServletInvocableHandlerMethodorg.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#createInvocableHandlerMethod
        -> new ServletInvocableHandlerMethod
    ->  ServletInvocableHandlerMethod 填充 argumentResolversreturnValueHandlersbinderFactory  parameterNameDiscoverer 属性
        -> 此时属性分别是 HandlerMethodArgumentResolverCompositeHandlerMethodReturnValueHandlerCompositeServletRequestDataBinderFactoryDefaultParameterNameDiscoverer

    -> 创建 ModelAndViewContainernew ModelAndViewContainer
    -> ModelAndViewContainer 初始化包括配置 InputFlashMap@SessionAttributes  @ModelAttribut 注解处理等

    -> 创建 AsyncWebRequest 实例 StandardServletAsyncWebRequestorg.springframework.web.context.request.async.WebAsyncUtils#createAsyncWebRequest
        ->  request  response 封装为 StandardServletAsyncWebRequest 实例new StandardServletAsyncWebRequest
        -> 始终创建实例与请求是否是异步无关
    -> 获取或创建 WebAsyncManager 实例org.springframework.web.context.request.async.WebAsyncUtils#getAsyncManager(javax.servlet.ServletRequest)
        -> 场景一获取servletRequest.getAttribute(WEB_ASYNC_MANAGER_ATTRIBUTE)debug 第一次请求成功获取
        -> 场景二创建new WebAsyncManager()
    -> 配置 WebAsyncManager包括 taskExecutorasyncWebRequestcallableInterceptorsdeferredResultInterceptors
        -> 当前未进行任何异步或线程池相关配置因此 this.taskExecutor 属性默认实例是 SimpleAsyncTaskExecutor
        -> this.callableInterceptors  this.deferredResultInterceptors 均为空集合
    -> if (asyncManager.hasConcurrentResult())则进行相关处理debug 时不满足条件

    -> 调用 handle 方法org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod#invokeAndHandle
        -> 调用方法org.springframework.web.method.support.InvocableHandlerMethod#invokeForRequest
            -> 解析方法参数org.springframework.web.method.support.InvocableHandlerMethod#getMethodArgumentValues
                -> 获取 HandlerMethod 方法的形式参数入参)。org.springframework.web.method.HandlerMethod#getMethodParameters
                -> for-each parameters
                    -> 如果方法入参 providedArgs 包含当前期望的 parameter则直接返回根据对象类型匹配org.springframework.web.method.HandlerMethod#findProvidedArgument
                        -> 目前发现正常请求不会使用 providedArgs仅异常处理相关会使用 providedArgsorg.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver#doResolveHandlerMethodException
                    -> 如果处理器不支持处理该参数则抛出异常 IllegalStateExceptionorg.springframework.web.method.support.HandlerMethodArgumentResolverComposite#supportsParameter
                        -> this.resolvers 的实例为 HandlerMethodArgumentResolverComposite
                        -> 查找匹配的处理器org.springframework.web.method.support.HandlerMethodArgumentResolverComposite#getArgumentResolver
                            -> 首先将 MethodParameter 作为 key 从缓存 this.argumentResolverCache 中获取
                            -> 如果缓存为空则遍历 this.argumentResolvers 查找匹配的处理器并存储到缓存
                                -> for-each this.argumentResolvers, org.springframework.web.method.support.HandlerMethodArgumentResolver#supportsParameter
                    -> 解析参数org.springframework.web.method.support.HandlerMethodArgumentResolverComposite#resolveArgument
                        -> 获取 ArgumentResolverorg.springframework.web.method.support.HandlerMethodArgumentResolverComposite#getArgumentResolver
                            -> 从缓存 this.argumentResolverCache 获取因为上一步已存储到缓存中因此缓存一定不为空否则抛出异常 IllegalArgumentException
                        -> 调用 resolverorg.springframework.web.method.support.HandlerMethodArgumentResolver#resolveArgument
                            -> debug 场景为 @RequestBody 注解参数因此调用 org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor#resolveArgument详情参见分支 RequestResponseBodyMethodProcessor#resolveArgument》。
            -> 调用 handler 方法org.springframework.web.method.support.InvocableHandlerMethod#doInvoke
                -> 反射调用 controller bean 中的方法method.invoke(getBean(), args);

        -> 适配 this.responseStatus ResponseStatus 注解的相关配置org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod#setResponseStatus
        -> 标识 response 响应体已处理无需视图处理mavContainer.setRequestHandled(false);
            -> 变量位置 org.springframework.web.method.support.ModelAndViewContainer#requestHandled

        -> 处理返回值org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite#handleReturnValue
            -> 查找匹配的方法org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite#handleReturnValue
                -> 选择org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite#selectHandler
                    -> 判断是否是 AsyncReturnValueorg.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite#isAsyncReturnValue
                        -> for-each this.returnValueHandlers校验条件是 handler instanceof AsyncHandlerMethodReturnValueHandler  AsyncHandlerMethodReturnValueHandler#isAsyncReturnValue
                    -> for-each this.returnValueHandlers 返回匹配的第一个org.springframework.web.method.support.HandlerMethodReturnValueHandler#supportsReturnType
            -> 执行方法org.springframework.web.method.support.HandlerMethodReturnValueHandler#handleReturnValue

    -> if (asyncManager.isConcurrentHandlingStarted()) 满足条件则返回 null

    -> 处理 ModelAndVieworg.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#getModelAndView

-> 如果响应体不包含 "Cache-Control" heander
    -> 如果当前请求包含了 session attribute则进行相关配置

END