参考视频:SpringMVC教程,SpringMVC从零到精通,老杜SpringMVC,动力节点SpringMVC

1. 从源码角度看执行流程

1.1 从源码角度分析SpringMVC执行流程

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
// 前端控制器,SpringMVC最核心的类
public class DispatcherServlet extends FrameworkServlet {
// 前端控制器最核心的方法,这个方法是负责处理请求的,一次请求,调用一次 doDispatch 方法。
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
// 通过请求获取处理器
// 请求:http://localhost:8080/springmvc/hello (有URI)
// 根据请求路径来获取对应的要执行的处理器
// 实际上返回的是一个处理器执行链对象
// 这个执行链(链条)把谁串起来了呢?把这一次请求要执行的所有拦截器和处理器串起来了。
// HandlerExecutionChain是一次请求对应一个对象
HandlerExecutionChain mappedHandler = getHandler(request);

// 根据处理器获取处理器适配器对象
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); // Handler就是我们写的Controller

// 执行该请求对应的所有拦截器中的 preHandle 方法
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}

// 调用处理器方法,返回ModelAndView对象
// 在这里进行的数据绑定,实际上调用处理器方法之前要给处理器方法传参
// 需要传参的话,这个参数实际上是要经过一个复杂的数据绑定过程(将前端提交的表单数据转换成POJO对象)
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

// 执行该请求对应的所有拦截器中的 postHandle 方法
mappedHandler.applyPostHandle(processedRequest, response, mv);

// 处理分发结果(本质上就是响应结果到浏览器)
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}

private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
@Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
@Nullable Exception exception) throws Exception {
// 渲染
render(mv, request, response);
// 执行该请求所对应的所有拦截器的afterCompletion方法
mappedHandler.triggerAfterCompletion(request, response, null);
}

protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
// 通过视图解析器进行解析,返回视图View对象
View view = resolveViewName(viewName, mv.getModelInternal(), locale, request);
// 调用视图对象的渲染方法(完成响应)
view.render(mv.getModelInternal(), request, response);
}

protected View resolveViewName(String viewName, @Nullable Map<String, Object> model,
Locale locale, HttpServletRequest request) throws Exception {
// 视图解析器
ViewResolver viewResolver;
// 通过视图解析器解析返回视图对象View
View view = viewResolver.resolveViewName(viewName, locale);
}
}


// 视图解析器接口
public interface ViewResolver {
View resolveViewName(String viewName, Locale locale) throws Exception;
}

// 视图解析器接口实现类也很多:ThymeleafViewResolver、InternalResourceViewResolver

// 视图接口
public interface View{
void render(@Nullable Map<String, ?> model, HttpServletRequest request, HttpServletResponse response)
throws Exception;
}

// 每一个接口肯定是有接口下的实现类,例如View接口的实现类:ThymeleafView、InternalResourceView....

1.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
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
101
102
103
104
105
106
107
分析这一行代码:
HandlerExecutionChain mappedHandler = getHandler(request);

1. HandlerExecutionChain:处理器执行链对象

2. HandlerExecutionChain中的属性:
public class HandlerExecutionChain{
// 底层对应的是一个HandlerMethod对象
// 处理器方法对象
Object handler = new HandlerMethod(.....);
// 该请求对应的所有的拦截器按照顺序放到了ArrayList集合中
// 所有的拦截器对象也都是在服务器启动的时候都创建好。
List<HandlerInterceptor> interceptorList;
}

3. HandlerMethod 是什么?

HandlerMethod是最核心的要执行的目标,翻译为:处理器方法。
注意:HandlerMethod 是在web服务器启动时初始化spring容器的时候,就创建好了。
这个类当中比较重要的属性包括:beanName和Method
例如,以下代码:
@Controller("userController")
public class UserController{
@RequestMapping("/login")
public String login(User user){
return ....
}
}
那么以上代码对应了一个HandlerMethod对象:
public class HandlerMethod{
private String beanName = "userController";
private Method loginMethod;
}

4. getHandler(request);
这个方法还是在DispatcherServlet类中。
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
if (this.handlerMappings != null) {
for (HandlerMapping mapping : this.handlerMappings) {
// 通过合适的 HandlerMapping才能获取到 HandlerExecutionChain对象。
// 如果你处理器方法使用了 @RequestMapping注解,那么以下代码中的mapping是:RequestMappingHandlerMapping对象。
HandlerExecutionChain handler = mapping.getHandler(request);
if (handler != null) {
return handler;
}
}
}
return null;
}

重点:
我们处理请求的第一步代码是:HandlerExecutionChain mappedHandler = getHandler(request);
其本质上是调用了:HandlerExecutionChain handler = mapping.getHandler(request);

mapping变量就是 HandlerMapping。
HandlerMapping是一个接口:
翻译为处理器映射器,专门负责映射的。就是本质上根据请求路径去映射处理器方法的。
HandlerMapping接口下有很多实现类:
例如其中一个比较有名的,常用的:RequestMappingHandlerMapping
这个 RequestMappingHandlerMapping 叫做:@RequestMapping注解专用的处理器映射器对象。

当然,如果你没有使用 @RequestMapping注解,也可以写xml配置文件来进行映射,那个时候对应的就是其他的HandlerMapping接口的实现类了。

HandlerMapping 对象也是在服务器启动阶段创建的,所有的HandlerMapping对象都是在服务器启动阶段创建,并且存放到集合中。
public class DispatcherServlet{
List<HandlerMapping> handlerMappings;
}

5. RequestMappingHandlerMapping中的 getHandler(request);
HandlerExecutionChain handler = mapping.getHandler(request);

mapping.getHandler(request);这个方法底层一定是获取了 HandlerMethod 对象,将其赋值给 HandlerExecutionChain的handler属性

public class RequestMappingHandlerMapping extends AbstractHandlerMethodMapping{
protected void registerHandlerMethod(Object handler, Method method, RequestMappingInfo mapping) {
super.registerHandlerMethod(handler, method, mapping);
updateConsumesCondition(mapping, method);
}
}

public class AbstractHandlerMethodMapping{
protected void registerHandlerMethod(Object handler, Method method, T mapping) {
this.mappingRegistry.register(mapping, handler, method);
}

public void register(T mapping, Object handler, Method method) {
HandlerMethod handlerMethod = createHandlerMethod(handler, method);
}

protected HandlerMethod createHandlerMethod(Object handler, Method method) {
if (handler instanceof String beanName) {
return new HandlerMethod(beanName,
obtainApplicationContext().getAutowireCapableBeanFactory(),
obtainApplicationContext(),
method);
}
return new HandlerMethod(handler, method);
}
}


这一步牵连到的类有哪些:
HandlerExecutionChain
HandlerMethod
HandlerInterceptor
HandlerMapping
RequestMappingHandlerMapping(是HandlerMaping接口的实现)

1.3 关于根据处理器来获取处理器适配器

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
分析:
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

1. 底层使用了适配器模式。

2. 每一个处理器(我们自己写的Controller),都有自己适合的处理器适配器。

3. 在SpringMVC当中处理器适配器也有很多种,其中一个比较有名的,常用的处理器适配器是:RequestMappingHandlerAdapter
这个处理器适配器是专门处理 “处理器方法”上有 @RequestMapping 注解的。

4. mappedHandler.getHandler() 获取的是 HandlerMethod 对象

5. HandlerAdapter也是一个接口:
其中有一个常用的实现类:RequestMappingHandlerAdapter

6. 在服务器启动阶段,所有的 HandlerAdapter接口的实现类都会创建出来。在服务器启动阶段!!!!!!
List<HandlerAdapter> handlerAdapters;

7. HandlerAdapter接口非常重要,通过这个接口来调用最终的 HandlerMethod。

8. HandlerAdapter是适配器,是对 HandlerMethod 进行的适配。

9. 在DispatcherServlet类中,如下代码:
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
if (this.handlerAdapters != null) {
for (HandlerAdapter adapter : this.handlerAdapters) {
if (adapter.supports(handler)) {
return adapter;
}
}
}
}

1.4 关于执行请求对应的拦截器preHandle

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
关于执行请求对应的拦截器的preHandle方法

DispatcherServlet:
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}


HandlerExecutionChain:
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
for (int i = 0; i < this.interceptorList.size(); i++) {
HandlerInterceptor interceptor = this.interceptorList.get(i);
if (!interceptor.preHandle(request, response, this.handler)) {
triggerAfterCompletion(request, response, null);
return false;
}
this.interceptorIndex = i;
}
return true;
}

遍历List集合,从List集合中取出每一个 HandlerInterceptor对象,调用 preHandle,i++,可见是顺序调用。

1.5 关于调用处理器方法

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
关于调用处理器方法:
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

ha 是处理器适配器

mv 是ModelAndView对象

这个方法是最核心的,调用请求路径对应的HandlerMethod。(调用处理器方法。)


ha是HandlerAdapter,如果是 @RequestMapping 注解对应的,那么就是 RequestMappingHandlerAdapter:

RequestMappingHandlerAdapter:
protected ModelAndView handleInternal(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
mav = invokeHandlerMethod(request, response, handlerMethod);
}
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
// 获取一个数据绑定工厂
WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
// 获取一个可调用的处理器方法
ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
// 给可调用的方法绑定数据
invocableMethod.setDataBinderFactory(binderFactory);
// 给可调用的方法设置参数
invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
// 可调用的方法执行了。
invocableMethod.invokeAndHandle(webRequest, mavContainer);
}

在HandlerAdapter中做的核心事情:
将前端提交的form数据通过 HttpMessageConverter 将其转换成 POJO对象。(数据转换)
并将数据绑定到 HandlerMethod 对象上。
调用HandlerMethod。
返回 ModelAndView

1.6 关于执行请求对应的拦截器的postHandle

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
DispatcherServlet:

mappedHandler.applyPostHandle(processedRequest, response, mv);

HandlerExecutionChain:

void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv)
throws Exception {

for (int i = this.interceptorList.size() - 1; i >= 0; i--) {
HandlerInterceptor interceptor = this.interceptorList.get(i);
interceptor.postHandle(request, response, this.handler, mv);
}
}

通过源码解决,可以很轻松的看到,从List集合中逆序(i--)逐一取出拦截器对象,并且调用拦截器的 postHandle方法。

1.7 关于处理分发结果

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

public class DispatcherServlet{

// 处理分发结果
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);

private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
@Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
@Nullable Exception exception) throws Exception {
// 渲染
render(mv, request, response);
}

protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
// 通过视图解析器进行解析,返回视图View对象
View view = resolveViewName(viewName, mv.getModelInternal(), locale, request);
// 调用视图对象的渲染方法(完成响应)
view.render(mv.getModelInternal(), request, response);
}

protected View resolveViewName(String viewName, @Nullable Map<String, Object> model,
Locale locale, HttpServletRequest request) throws Exception {
// 视图解析器
ViewResolver viewResolver;
// 通过视图解析器解析返回视图对象View
View view = viewResolver.resolveViewName(viewName, locale);
}
}


// 视图解析器接口
public interface ViewResolver {
View resolveViewName(String viewName, Locale locale) throws Exception;
}

// 视图解析器接口实现类也很多:ThymeleafViewResolver、InternalResourceViewResolver

// 视图接口
public interface View{
void render(@Nullable Map<String, ?> model, HttpServletRequest request, HttpServletResponse response)
throws Exception;
}

// 每一个接口肯定是有接口下的实现类,例如View接口的实现类:ThymeleafView、InternalResourceView....

1.8 关于执行拦截器的afterCompletion方法

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
DispatcherServlet:

private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
@Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
@Nullable Exception exception) throws Exception {
// 渲染
render(mv, request, response);
// 执行该请求所对应的所有拦截器的afterCompletion方法
mappedHandler.triggerAfterCompletion(request, response, null);
}

HandlerExecutionChain:

void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex) {
for (int i = this.interceptorIndex; i >= 0; i--) {
HandlerInterceptor interceptor = this.interceptorList.get(i);
try {
interceptor.afterCompletion(request, response, this.handler, ex);
}
catch (Throwable ex2) {
logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
}
}
}

通过源码可以看出,也是通过逆序(i--)的方式进行拦截器的调用,调用拦截器的afterCompletion方法。

2. 从图片角度看执行流程

SpringMVC执行流程

3. WEB服务器启动时都做了什么

先搞明白核心类的继承关系:

DispatcherServlet extends FrameworkServlet extends HttpServletBean extends HttpServlet extends GenericServlet implements Servlet

服务器启动阶段完成了:

  1. 初始化Spring上下文,也就是创建所有的bean,让IoC容器将其管理起来。
  2. 初始化SpringMVC相关的对象:处理器映射器,处理器适配器等。。。
WEB服务器启动(1) WEB服务器启动(2) WEB服务器启动(3) WEB服务器启动(4) WEB服务器启动(5) WEB服务器启动(6) WEB服务器启动(7) WEB服务器启动(8)