盘点 SpringMVC MVC 主流程

首先分享之前的所有文章 , 欢迎点赞收藏转发三连下次一定 >>>> 😜😜😜

文章合集 : 🎁 juejin.cn/post/694164…

Github : 👉 github.com/black-ant

CASE 备份 : 👉 gitee.com/antblack/ca…

一 . 前言

文章目标 :

  • 梳理 SpringMVC 主流程中的相关逻辑
  • 确定 相关流程得参数

本文章未涉及的部分:

  • MVC 的配置
  • 容器的初始化
  • 容器的加载
  • 等….

二 . 流程分析

此主要流程包括如下几个部分 :

  • 注解的扫描处理
  • 请求的拦截
  • 请求的转换
  • 请求的最终处理

image.png

2.1 注解的扫描处理

注解的扫描主要在 DispatcherServlet.initHandlerMappings 中 , 其逻辑处理类在 AbstractHandlerMethodMapping.getHandlerInternal 中.

2.1.1 注解的扫描

注解扫描的起点主要是 RequestMappingHandlerMapping , 其中做了这几件事 :

  • 在 AbstractHandlerMethodMapping 中通过 InitializingBean 的 afterPropertiesSet 处理所有的方法
    • detectHandlerMethods 中进行核心的处理
  • 对 RequestMapping 进行了扫描操作 , 并且生成 RequestMappingInfo
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
java复制代码
C31- RequestMappingHandlerMapping : 扫描的起点 , 因为类实现了 InitializingBean 接口 , 其核心基于 afterPropertiesSet
M- afterPropertiesSet
?- 这个方法中主要对 RequestMappingInfo.BuilderConfiguration 进行配置 ,最后调用父类 afterPropertiesSet 方法

C32- AbstractHandlerMethodMapping
M32_01- afterPropertiesSet
- initHandlerMethods() : 核心方法 , 对 Handler Method 进行处理 -> M32_02
M32_02- initHandlerMethods
?- 扫描ApplicationContext中的bean,检测和注册处理程序方法
- 获取所有的 BeanName , 调用 processCandidateBean 执行 -> M32_03
M32_03- processCandidateBean
- obtainApplicationContext().getType 获取具体的 Class 类
- 通过 isHandler 判断是否包含 Controller 或者 RequestMapping
?- RestController 继承了 Controller
- 如果需要处理 , 调用 detectHandlerMethods 处理 -> M32_04
M32_04- detectHandlerMethods
- 同样的 , 通过传入的 handle (类的别名) 获取对应的 Class<?>
- 获取所有的标注了注解的集合 Map<Method, T> -> ps:M32_04_01
- getMappingForMethod 获取注解对应的 Condition -> ps:M32_04_01 详细流程
- selectMethods
FOR- 循环所有的 methods , 首先搜索可用的代理 , 注册对应的 Bean
?- 代理是 Spring 中很重要的一环 , 后面开单章详细说
M32_05- registerHandlerMethod
- 注册到 MappingRegistry


// ps:M32_04_01 流程详细分析
Map<Method, T> methods = MethodIntrospector.selectMethods(userType,(MethodIntrospector.MetadataLookup<T>) method -> {
return getMappingForMethod(method, userType);
});

// 可以看到 , 其中核心的方法有2个 getMappingForMethod / selectMethods
getMappingForMethod 会返回Mapping 对应的 Condition , 例如 patternsCondition / methodCondition


// ps:M32_04_01
protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
// 此处对 RequestMapping 进行了扫描操作
// 代码比较简单 , 就是 AnnotatedElementUtils.findMergedAnnotation 后构建了一个 RequestMappingInfo bean
RequestMappingInfo info = createRequestMappingInfo(method);
if (info != null) {
// 此处是获取 Class 类上面的 RequestMapping
RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType);
if (typeInfo != null) {
// 对2者进行组合 , 生成新的 Bean 对象
// 注意是类 组合 方法
// 主要是覆盖和合并 , url 比较特殊 , 变化为 /get -> /cookie/get
info = typeInfo.combine(info);
}

// 前缀 path 的处理 , 该属性在配置 PathMatchConfigurer 时处理 , 可以通过 addPathPrefix 添加
String prefix = getPathPrefix(handlerType);
if (prefix != null) {
info = RequestMappingInfo.paths(prefix).options(this.config).build().combine(info);
}
}
return info;
}

2.1.2 Bean 的注册

上面的环节已经对 Mapping Method 扫描完成 , 在此环节中进行注册 , 注册主要使用内部类MappingRegistry
, 其内部存在多个 Map ,用于保存地址的映射关系

(url -MappingRegistration/HandlerMethod/CorsConfiguration 等 )

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
java复制代码            
C- AbstractHandlerMethodMapping
VC33- MappingRegistry : 内部类
F33_01- Map<T, MappingRegistration<T>> registry = new HashMap<>();
F33_02- Map<T, HandlerMethod> mappingLookup = new LinkedHashMap<>();
F33_03- MultiValueMap<String, T> urlLookup = new LinkedMultiValueMap<>();
F33_04- Map<String, List<HandlerMethod>> nameLookup = new ConcurrentHashMap<>();
F33_05- Map<HandlerMethod, CorsConfiguration> corsLookup = new ConcurrentHashMap<>();
M33_01- register(T mapping, Object handler, Method method) -> PS:M33_01
?- 此处主要是为了构建 Map 集合 , 用于映射时匹配
1- 通过 handler 和 Method 构建了使用时的主要单元Bean HandlerMethod
2- 以 RequestMappingInfo(mapping) 为key 将 HandlerMethod 放入 Map (F33_02) 集合
3- 以 URL 字符串为 key , 将 以 RequestMappingInfo(mapping) 放入 Map 集合 (F33_03)
4- 以 Name (策略类构建特殊的 mappingName)为 key , 将 handlerMethod 放入 Map (F33_04) -> PS:M33_02
5- 以 HandlerMethod 为 key , 将 CorsConfiguration 放入集合 Map (F33_05)
6- 以 RequestMappingInfo(mapping) 为key , 生成一个 MappingRegistration 放入集合 registry (F33_01)


// PS:M33_01 register 方法的关键和亮点
1- 使用 ReentrantReadWriteLock 保证多线程下访问的唯一性 , 在 finally 中解锁

// PS:M33_02 特殊的命名方式 RequestMappingInfoHandlerMethodMappingNamingStrategy
这里主要通过 RequestMappingInfoHandlerMethodMappingNamingStrategy 类生成对应的 Name


// M33_01 伪代码
public void register(T mapping, Object handler, Method method) {
this.readWriteLock.writeLock().lock();
try {
// 1- 通过 handler 和 Method 构建了使用时的主要单元Bean HandlerMethod
HandlerMethod handlerMethod = createHandlerMethod(handler, method);
validateMethodMapping(handlerMethod, mapping);

// 2- 以 RequestMappingInfo(mapping) 为key 将 HandlerMethod 放入 Map (F33_02) 集合
this.mappingLookup.put(mapping, handlerMethod);

List<String> directUrls = getDirectUrls(mapping);
for (String url : directUrls) {
// 3- 以 URL 字符串为 key , 将 以 RequestMappingInfo(mapping) 放入 Map 集合 (F33_03)
this.urlLookup.add(url, mapping);
}

String name = null;
if (getNamingStrategy() != null) {
name = getNamingStrategy().getName(handlerMethod, mapping);
// 4- 以 Name (策略类构建特殊的 mappingName)为 key , 将 handlerMethod 放入 Map (F33_04)
addMappingName(name, handlerMethod);
}

// 构建跨域配置
CorsConfiguration corsConfig = initCorsConfiguration(handler, method, mapping);
if (corsConfig != null) {
5- 以 HandlerMethod 为 key , 将 CorsConfiguration 放入集合 Map (F33_05)
this.corsLookup.put(handlerMethod, corsConfig);
}
// 6- 以 RequestMappingInfo(mapping) 为key , 生成一个 MappingRegistration 放入集合 registry
this.registry.put(mapping, new MappingRegistration<>(mapping, handlerMethod, directUrls, name));
}finally {
this.readWriteLock.writeLock().unlock();
}
}


// 自此 , Mapper 的前期准备就完成了

MvcUrl001.jpg

HandlerMappingCondition.jpg

2.2 请求的来临

请求的入口还是通过 Servlet 来完成的 , 先看一下 Servlet 体系 PS:51_01

2.2.1 起点 : 初始化一个 Servlet

MVC 是基于 Servlet 的体系结构 , 其最初的起点是通过 StandardWrapper 进行 initServlet 开始
流转路径如下 :

1
java复制代码StandardWrapper -> GenericServlet (init) -> HttpServletBean (init) -> FrameworkServlet (initServletBean)

看一个很老的图 , 大概对 DispatcherServlet 有个初步的了解 :

mvc-context-hierarchy.png

2.2.2 核心 : DispatchServlet 的初始化

1
2
3
4
5
java复制代码C51- DispatcherServlet 
M51_10- initHandlerMappings(ApplicationContext context)
?- 这个方法的核心操作就是初始化 handlerMappings -> PS:M51_10_01
- 通过 BeanFactoryUtils 构建所有的 Mapping 类型结合
- 为 Map 进行排序

Filter 处理逻辑 , Filter 分为 3步 : 初始化 , 拦截 , 销毁 , 此处主要是初始化操作 >>

Filter 不是 Spring 专属的对象 , 其归属于 Servlet 原生体系 , 主要有以下2个流程


子流程一 : 核心处理容器 : StandardContext,添加 Filter 流程

  • ServletWebServerApplicationContext # selfInitialize : 获取所有的需要处理的 Filter 类
  • ServletContextInitializerBeans # ServletContextInitializerBeans : 从 Factory 中获取具体的类
  • RegistrationBean # onStartup : 启动 并且注册 FilterBean
  • StandardContext # addFilterDef : 添加 FilterDef , 即 filter definition
1
2
3
4
5
6
7
8
9
10
java复制代码                  
C- ServletWebServerApplicationContext
M- selfInitialize
- getServletContextInitializerBeans 其中会获取所有的 Beans , 分别调用 beans.onStartup 启动
M- getServletContextInitializerBeans
- 核心处理逻辑在 ServletContextInitializerBeans 中

C- ServletContextInitializerBeans
M- ServletContextInitializerBeans(ListableBeanFactory beanFactory,Class<? extends ServletContextInitializer>... initializerTypes)
?- 此方法中会获取 Servlet 和 Filter 的初始化类 --> TODO : 后续单独分析 Serlvet 时看

子流程二 : 调用 Filter 初始化流程

这是一个异步操作 : 通过一个 call 流程异步处理 , 具体的流程在 org.apache.catalina.core 中

  • StandardContext # filterStart : Set filterDefs.entrySet 中获取所有的 Filter
  • ApplicationFilterConfig : 构建一个 ApplicationFilterConfig 并且在其中调用 initFilter() 初始化
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
java复制代码            
// Filter 的拦截调用
Filter 的核心思路就是 FilterChain 的链表调用 . 其起点为 ApplicationFilterChain
C- ApplicationFilterChain
F- private ApplicationFilterConfig[] filters = new ApplicationFilterConfig[0];
- 选择一个 ApplicationFilterConfig , 调用 doFilter , 并且把当前对象传入
?- 后续就是调用链的逻辑




// HandlerInterceptor 的处理流程
- 与 Filter 不同的是 , 这里的 HandlerInterceptor 是 Spring 体系中的对象
- 拦截器主要在 WebMvcConfigurer 通过 InterceptorRegistry 手动注入

@Override
public void addInterceptors(InterceptorRegistry registry) {
logger.info("------> this is addInterceptors <-------");
registry.addInterceptor(new ConfigInterceptor());
}

// Interceptor 的初始化
Interceptor 的主要起点是 WebMvcConfigurationSupport
C- WebMvcConfigurationSupport
M- requestMappingHandlerMapping
- 其中会为当前 Mapping 添加 Interceptor


// Interceptor 的调用
Interceptor 的主调流程位于 HandlerExecutionChain
C- HandlerExecutionChain
M- applyPreHandle
- getInterceptors() 获取 HandlerInterceptor->LV001 数组
FOR- 循环 HandlerInterceptor:LV001 调用 preHandle


// DispatcherServlet 衔接到 RequestMapping 映射关联
- ApplicationFilterChain 处理完成 Filter
// 这里会进行一次继承类的循环调用
C- DispatcherServlet
M- FrameworkServlet
M- HttpServlet

- HttpServlet 执行 service(ServletRequest req, ServletResponse res) 方法
- FrameworkServlet 执行 service(HttpServletRequest request, HttpServletResponse response) 方法
- HttpServlet 执行 service(HttpServletRequest request, HttpServletResponse response) 方法
- FrameworkServlet 执行 doGet 处理请求
- FrameworkServlet 执行 processRequest 开始完整处理
- 来到具体实现类 DispatcherServlet

PS:51_01 Servlet 家族体系
ServletModule.png

PS:M51_10_01 HandlerMapping 家族体系
HandlerMappingModule.png

2.3 请求的解析

servlet 的起始方法是 HttpServlet , Spring 部分的核心方法是实现类FrameworkServlet

解析前置处理操作

  • 在 Reuqest 和 Response 转换为 HttpServletRequest 和 HttpServletResponse 后
  • 调用 HttpServlet 中 service(HttpServletRequest req, HttpServletResponse resp) 方法 , 触发 FrameworkServlet doGet 方法
  • 最终进入 DispatcherServlet 核心类 , 处理一个 Http 请求

2.3.1 DispatcherServlet 获取处理 Handler

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
java复制代码Start -> HttpServlet
// TODO : Dispatch 具体流程以后单独分析 , 这里先简单过一下
C51- DispatcherServlet
M51_01- doService(HttpServletRequest request, HttpServletResponse response)
?- 执行 Service 处理请求
- 调用 M51_02 执行具体的流程
M51_02- doDispatch(HttpServletRequest request, HttpServletResponse response)
1- WebAsyncUtils.getAsyncManager(request) : 准备异步处理管理器 WebAsyncManager -> PS:M51_02_01
2- checkMultipart(request) : 尝试解析 Multipart Request -> PS:M51_02_02
3- getHandler(processedRequest) : 获取具体需要执行的 Handler -> M51_03
?- 未找到对应的 Handler 会直接 return
4- getHandlerAdapter(mappedHandler.getHandler()) : 确定当前请求的处理程序适配器 -> PS:M51_02_04
5- 处理 Get-Head 请求 -> PS:M51_02_05
- mappedHandler.applyPreHandle : 前置处理
6- 调用 HandlerAdapter 处理 请求
7- applyDefaultViewName : view 名称的解析 , 此环节不分析
- mappedHandler.applyPostHandle : 后置处理 -> PS:M51_02_09
M51_03- getHandler
M51_04- getHandlerAdapter

// M51_03 源代码
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
if (this.handlerMappings != null) {
for (HandlerMapping mapping : this.handlerMappings) {
HandlerExecutionChain handler = mapping.getHandler(request);
if (handler != null) {
return handler;
}
}
}
return null;
}


// M51_04 getHandlerAdapter 源代码
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
if (this.handlerAdapters != null) {
for (HandlerAdapter adapter : this.handlerAdapters) {
// 太常见的处理方式 , 循环处理中通过 support 判断
if (adapter.supports(handler)) {
return adapter;
}
}
}
throw new ServletException("....");
}

PS:M51_02_01 WebAsyncManager 介绍

  • 作用 : 用于管理异步请求处理的中心类,主要用作SPI,通常不被应用程序类直接使用
  • 核心 : 通过多个不同的线程 , 处理请求和结果
  • 流程
    1. 异步场景以线程(T1)中正常的请求处理开始
    2. 并发请求处理可以通过调用startCallableProcessing或startDeferredResultProcessing来启动,这两种方法都会在单独的线程(T2)中产生一个结果。
    3. 保存结果并将请求分发给容器,以便在第三个线程(T3)中继续处理保存的结果。
    4. 在已分派线程(T3)中,可以通过getConcurrentResult()访问保存的结果,或者通过hasConcurrentResult()检测其是否存在。

PS:M51_02_02 : checkMultipart 的目的

为什么这里需要校验一下 checkMultipart ? 其底层主要做了如下几件事 :

  • 判断是否有 multipartResolver 并且用该解析器判断是否为Multipart
  • 如果以上条件达成 , multipartResolver.resolveMultipart(request) 进行解析返回新 Request
  • 否则返回原有 request

说白了 , 就是 multipart request 的处理 , 但是相对的问题又来了 >>> 什么是 multipart request ?

作用 : HTTP 多部分请求是 HTTP 客户机构造的 HTTP 请求,用于将文件和数据发送到 HTTP 服务器。

场景 : 浏览器和 HTTP 客户端通常使用它将文件上传到服务器。


PS:M51_02_04 getHandler 和 getHandlerAdapter 的区别 ?

1
2
3
4
5
6
7
8
9
10
java复制代码getHandler -> HandlerExecutionChain
getHandlerAdapter -> HandlerAdapter

// HandlerExecutionChain 的作用 :
- HandlerExecutionChain 是 Handler 的处理器链 , 其中包含了 HandlerInterceptor 的数组和对应的 Handler

// HandlerAdapter 的作用 :
- 首先 , 看名字就知道 , 这是个适配器 , 适配器能在原有功能上扩展新的功能
- MVC框架SPI,允许参数化核心MVC工作流 , 该接口用于允许DispatcherServlet无限扩展。
- DispatcherServlet通过这个接口访问所有已安装的处理程序

HandlerAdapter_system.png

PS:M51_02_05 GET/HEAD 请求细说

这地方老有意思了 ,刚接触代码那会这里出问题想了好久才知道有这么个东西

参考文档 @ www.cnblogs.com/longyongzhe…

特点 : HEAD方法跟GET方法相同,只不过服务器响应时不会返回消息体。一个HEAD请求的响应中,HTTP头中包含的元信息应该和一个GET请求的响应消息相同。这种方法可以用来获取请求中隐含的元信息,而不用传输实体本身。也经常用来测试超链接的有效性、可用性和最近的修改。

作用 :

  1. 只请求资源的首部;
  2. 检查超链接的有效性;
  3. 检查网页是否被修改;
  4. 多用于自动搜索机器人获取网页的标志信息,获取rss种子信息,或者传递安全认证信息等

PS:M51_02_09 前置处理和后置处理主要处理什么 ?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
java复制代码- mappedHandler.applyPreHandle : 前置处理
- mappedHandler.applyPostHandle : 后置处理

// 这2个方法主要是对拦截器的处理 , 可以看到其中直接调用拦截器的方法
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
HandlerInterceptor[] interceptors = getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
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;
}

M51_02 : 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
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
java复制代码
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;

// 准备异步处理管理器 WebAsyncManager
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

try {
ModelAndView mv = null;
Exception dispatchException = null;

try {
// 尝试解析 Multipart Request
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);

// 获取具体需要执行的 Handler
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return;
}

// 确定当前请求的处理程序适配器
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

// 处理 Get-Head 请求
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}

// 拦截器前置处理
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}

// 调用 HandlerAdapter 处理 请求
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

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

applyDefaultViewName(processedRequest, mv);
// 拦截器后置处理
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);
}
}
}
}

2.3.2 HandlerMapping 解析到方法

上文中已经获取到了 Adapter , 以下就是 Adapter 的详细处理

流程处理

流程处理分为2个部分 , 简单点说就是 :

  • getHandler 获取使用的 MethodHandler
  • getHandlerAdapter 获取适配处理器
  • 通过适配处理器处理 MethodHandler

一 : 获取处理的 Handler (getHandler)

DispatcherServlet # M51_03- getHandler 中可以看到 , 通过 HandlerExecutionChain # getHandler 获取 Handler 对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
java复制代码C76- AbstractHandlerMapping 
M76_01- HandlerExecutionChain getHandler(HttpServletRequest request) : 构建处理链
- getHandlerInternal(request) 获取处理的 Handler -> M32_01
- 通过 Handler 构建 HandlerExecutionChain TODO
- 跨域配置的处理 CorsConfiguration
M76_02- getHandlerInternal
- 调用 父类 -> M32_01

C32- AbstractHandlerMethodMapping
M32_01- getHandlerInternal(HttpServletRequest request)
- 先配置了一个读锁
- 调用 lookupHandlerMethod -> M32_02
M32_02- lookupHandlerMethod : 对请求做真正的处理 , 获取 HandlerMethod
1- 构建 List<Match> 用于存放匹配结果
- MappingRegistry 通过 lookupPath 获取对象 List<RequestMappingInfo>
?- 底层实际上是调用上文初始化使用的 urlLookup.get(urlPath)
- 调用 addMatchingMappings , 将匹配的 Match放入 1 步构建的 List 中
- 返回处理的 Method

M32_02 lookupHandlerMethod 请求处理

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
java复制代码protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
List<Match> matches = new ArrayList<>();
// 从 MappingRegistry 中获取 Mapping List
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()) {
// {POST /test/getBody}
Match bestMatch = matches.get(0);
// 进行匹配 , 获取对应的 HandlerMethod
if (matches.size() > 1) {
Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
matches.sort(comparator);
bestMatch = matches.get(0);
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(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE, lookupPath) -> PS:M32_02_01
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);
}
}

// PS:M32_02_01
String PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE = HandlerMapping.class.getName() + ".pathWithinHandlerMapping";

步骤二 : 使用获取的 Handler (HandlerAdapter.handle)

从步骤一中我们已经获取到了 HandleMethod , 后续就是相关的处理逻辑

  • DispatcherServlet # doDispatch : 请求入口
  • AbstractHandlerMethodAdapter # handle : RequestMappingAdapter 的父入口
  • RequestMappingHandlerAdapter # handleInternal :请求处理主流程
  • RequestMappingHandlerAdapter # invokeHandlerMethod
  • ServletInvocableHandlerMethod # invokeAndHandle
  • InvocableHandlerMethod # invokeForRequest
  • InvocableHandlerMethod # doInvoke
  • Method # invoke : Java 反射到方法

步骤2-1 : RequestMappingHandlerAdapter # handleInternal 处理

在该方法中 , 如果需要视图解析,则调用准备ModelAndView的RequestMapping处理程序方法

核心 : ModelAndView 的准备

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
java复制代码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);

// 扩展InvocableHandlerMethod,通过注册的HandlerMethodReturnValueHandler处理返回值
ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
if (this.argumentResolvers != null) {
invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
}
if (this.returnValueHandlers != null) {
invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
}
invocableMethod.setDataBinderFactory(binderFactory);
invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);

// ModuleAndView 容器
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();
invocableMethod = invocableMethod.wrapConcurrentResult(result);
}

invocableMethod.invokeAndHandle(webRequest, mavContainer);
if (asyncManager.isConcurrentHandlingStarted()) {
return null;
}

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

ModelAndViewContainer 参数详情 :

image.png

1
2
3
4
5
6
7
8
9
10
11
12
java复制代码



// Web 模块最终步骤
C- InvocableHandlerMethod


// 代码最终步骤 : 调用 Method 的 invoke 方法 , 去完成具体的逻辑
C39- Method
M39_01- invoke(Object obj, Object... args)
?- 通过此方法调用最后的代理类 . java 反射包中方法 ,省略

2.4 补充 : 属性的转换

属性转换的主要类是 RequestMappingHandlerAdapter , 其主要调用逻辑为 :

  • C90- RequestMappingHandlerAdapter # M90_1- invokeHandlerMethod
  • C91- ServletInvocableHandlerMethod # M91_1- invokeAndHandle
  • C92- InvocableHandlerMethod # M92_1- invokeForRequest : 对请求进行处理
  • C93- InvocableHandlerMethod # M93_1- getMethodArgumentValues : 获取参数
  • C94- HandlerMethodArgumentResolverComposite # M94_1- resolveArgument : 解析参数
  • C95- RequestResponseBodyMethodProcessor # M95_1- readWithMessageConverters : 转换参数
  • C96- AbstractMessageConverterMethodArgumentResolver # M96_1- readWithMessageConverters : 最终处理逻辑
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
java复制代码C- RequestMappingHandlerAdapter
M- invokeHandlerMethod(HttpServletRequest request,HttpServletResponse response, HandlerMethod handlerMethod)
- invocableMethod.invokeAndHandle(webRequest, mavContainer)

// Step 1 : 处理的入口
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {

// 将 Request 解析处理
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);
try {
this.returnValueHandlers.handleReturnValue(returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
} catch (Exception ex) {
throw ex;
}
}


// PS : invokeForRequest 中主要流程
C- InvocableHandlerMethod
M- invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,Object... providedArgs)
- getMethodArgumentValues(request, mavContainer, providedArgs)
?- 详见下文参数获取

Step 2 : 参数的获取

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
java复制代码    protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {

MethodParameter[] parameters = getMethodParameters();
if (ObjectUtils.isEmpty(parameters)) {
return EMPTY_ARGS;
}

// 构建一个 Object 数组用于存放 param
Object[] args = new Object[parameters.length];
for (int i = 0; i < parameters.length; i++) {
MethodParameter parameter = parameters[i];
parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
args[i] = findProvidedArgument(parameter, providedArgs);
if (args[i] != null) {
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) {
throw ex;
}
}
return args;
}



public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {

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

Step 3 : RequestResponseBodyMethodProcessor 解析 RequestBody

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
java复制代码 
public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {

parameter = parameter.nestedIfOptional();
// 读取并且转换为相关对象
Object arg = readWithMessageConverters(webRequest, parameter, parameter.getNestedGenericParameterType());
String name = Conventions.getVariableNameForParameter(parameter);

if (binderFactory != null) {
WebDataBinder binder = binderFactory.createBinder(webRequest, arg, name);
if (arg != null) {
validateIfApplicable(binder, parameter);
if (binder.getBindingResult().hasErrors() && isBindExceptionRequired(binder, parameter)) {
throw new MethodArgumentNotValidException(parameter, binder.getBindingResult());
}
}
if (mavContainer != null) {
mavContainer.addAttribute(BindingResult.MODEL_KEY_PREFIX + name, binder.getBindingResult());
}
}
return adaptArgumentIfNecessary(arg, parameter);
}


// Step : 转换操作入口
protected <T> Object readWithMessageConverters(NativeWebRequest webRequest, MethodParameter parameter,
Type paramType) throws IOException, HttpMediaTypeNotSupportedException, HttpMessageNotReadableException {

HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class);
ServletServerHttpRequest inputMessage = new ServletServerHttpRequest(servletRequest);

Object arg = readWithMessageConverters(inputMessage, parameter, paramType);
if (arg == null && checkRequired(parameter)) {
throw new HttpMessageNotReadableException("Required request body is missing: " +
parameter.getExecutable().toGenericString(), inputMessage);
}
return arg;
}

Step end : 最终处理

最终处理中, 对 属性参数进行了最后的映射

PS: M96_1_01 继承体系

  • C- EmptyBodyCheckingHttpInputMessage
  • C- HttpInputMessage
  • C- HttpMessage

PS:M96_01_02 , 所有的 MessageConverter

  • ByteArrayHttpMessageConverter
  • StringHttpMessageConverter
  • ResourceHttpMessageConverter
  • ResourceRegionHttpMessageConverter
  • SourceHttpMessageConverter
  • AllEncompassingFormHttpMessageConverter
  • Jaxb2RootElementHttpMessageConverter
  • MappingJackson2HttpMessageConverter
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
java复制代码protected <T> Object readWithMessageConverters(HttpInputMessage inputMessage, MethodParameter parameter,
Type targetType) throws IOException, HttpMediaTypeNotSupportedException, HttpMessageNotReadableException {

MediaType contentType;
boolean noContentType = false;
try {
// 内容类型 : application/json;charset=UTF-8
contentType = inputMessage.getHeaders().getContentType();
} catch (InvalidMediaTypeException ex) {
throw new HttpMediaTypeNotSupportedException(ex.getMessage());
}
if (contentType == null) {
noContentType = true;
contentType = MediaType.APPLICATION_OCTET_STREAM;
}

// Controller 类
Class<?> contextClass = parameter.getContainingClass();
// 实体类 class
Class<T> targetClass = (targetType instanceof Class ? (Class<T>) targetType : null);
if (targetClass == null) {
ResolvableType resolvableType = ResolvableType.forMethodParameter(parameter);
targetClass = (Class<T>) resolvableType.resolve();
}

// 获取请求类型
HttpMethod httpMethod = (inputMessage instanceof HttpRequest ? ((HttpRequest) inputMessage).getMethod() : null);
Object body = NO_VALUE;

EmptyBodyCheckingHttpInputMessage message;
try {
// PS: M96_1_01
message = new EmptyBodyCheckingHttpInputMessage(inputMessage);

// 获取所有的 HttpMessageConverter -> PS:M96_01_02
for (HttpMessageConverter<?> converter : this.messageConverters) {
Class<HttpMessageConverter<?>> converterType = (Class<HttpMessageConverter<?>>) converter.getClass();
GenericHttpMessageConverter<?> genericConverter =
(converter instanceof GenericHttpMessageConverter ? (GenericHttpMessageConverter<?>) converter : null);
// 此处主要是 MappingJackson2HttpMessageConverter
if (genericConverter != null ? genericConverter.canRead(targetType, contextClass, contentType) :
(targetClass != null && converter.canRead(targetClass, contentType))) {
if (message.hasBody()) {
// 转换核心流程 -> PS:M96_01_02
// 主要为 Header
HttpInputMessage msgToUse =
getAdvice().beforeBodyRead(message, parameter, targetType, converterType);
body = (genericConverter != null ? genericConverter.read(targetType, contextClass, msgToUse) :
((HttpMessageConverter<T>) converter).read(targetClass, msgToUse));
body = getAdvice().afterBodyRead(body, msgToUse, parameter, targetType, converterType);
} else {
body = getAdvice().handleEmptyBody(null, message, parameter, targetType, converterType);
}
break;
}
}
} catch (IOException ex) {
throw new HttpMessageNotReadableException("I/O error while reading input message", ex, inputMessage);
}

if (body == NO_VALUE) {
if (httpMethod == null || !SUPPORTED_METHODS.contains(httpMethod) ||(noContentType && !message.hasBody())) {
return null;
}
throw new HttpMediaTypeNotSupportedException(contentType, this.allSupportedMediaTypes);
}

MediaType selectedContentType = contentType;
Object theBody = body;
LogFormatUtils.traceDebug(logger, traceOn -> {
String formatted = LogFormatUtils.formatValue(theBody, !traceOn);
return "Read \"" + selectedContentType + "\" to [" + formatted + "]";
});

return body;
}

PS:M96_01_02 参数详情

convert_body.jpg

convert_maptoUser.jpg

2.5 补充 : Response 的转换

属性的转换主要在 HandlerMethodReturnValueHandlerComposite 中进行 , 主要的逻辑为 :

  • C- InvocableHandlerMethod # invokeForRequest
  • C- ServletInvocableHandlerMethod # invokeAndHandle
  • C- HandlerMethodReturnValueHandlerComposite # handleReturnValue : 调用 Handler 处理
  • C- RequestResponseBodyMethodProcessor # handleReturnValue
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
java复制代码// - C91- ServletInvocableHandlerMethod  # M91_1- invokeAndHandle
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);
try {
// 此处进行 return 处理 : HandlerMethodReturnValueHandlerComposite
this.returnValueHandlers.handleReturnValue(
returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
} catch (Exception ex) {
throw ex;
}
}


// HandlerMethodReturnValueHandlerComposite # handleReturnValue
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {

HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType);
if (handler == null) {
throw new IllegalArgumentException("Unknown return value type: " + returnType.getParameterType().getName());
}
handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
}

// RequestResponseBodyMethodProcessor
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest)
throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {

mavContainer.setRequestHandled(true);
ServletServerHttpRequest inputMessage = createInputMessage(webRequest);
ServletServerHttpResponse outputMessage = createOutputMessage(webRequest);

// 此处进行返回处理 , 本次先不深入 , 以后单独看看返回的处理
writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);
}

总结

总算是把 MVC 写完了 , 本来篇幅不大 ,结果越写越多 , 反而不容易说清楚了.

初始化阶段中 , RequestMappingHandlerMapping 调用 initHandlerMethods 完成对所有的 Bean 进行扫描 , 最后构建 RequestMappingInfo 再通过 MappingRegistry 进行注册

在调用的阶段 , 首先调用 DispatcherServlet , 它会调用 AbstractHandlerMapping 中 getHandler 获取 HandlerMapping ( lookupHandlerMethod 调用 MappingRegistry 进行匹配)

匹配完成后 , 会来到 Adapter 主逻辑 , RequestMappingHandlerAdapter 中进行 ModelAndView 等处理 , 同时调用 ServletInvocableHandlerMethod 进行方法的映射

在方法映射阶段 , 会来到 InvocableHandlerMethod 类 , 首先会进行参数的解析和映射 , 最后通过 AbstractMessageConverterMethodArgumentResolverHttpMessageConverter 进行联合处理

映射完成后 , 就会 invoke 到对应的方法 , 同时通过 HandlerMethodReturnValueHandlerCompositeRequestResponseBodyMethodProcessor 进行 Response 的处理

更新日志

V20210821 更新流程图及总结

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

0%