SpringMVC之三个Servlet

一、HttpServletBean

参与创建工作,没有涉及请求的处理

二、FrameworkServlet

当第一个请求过来时,就初始化容器


如上图,当第一个请求过来时,FrameworkServlet就初始化容器,并将Spring的容器进行刷新,而DispatcherServlet的onRefresh刷新只是初始化九大组件。以后的请求就都不需要初始化容器。
初始化完容器以后,因为FrameworkServlet重写了Servlet的service,doGet,doPost等方法,所以会先走到Framework的doGet或者doPost等请求方法。
FrameworkServlet的设计很有趣,它将所有的请求get,post,delete等请求全部嫁接到
processRequest(request,response)

doService(request,response) 方法中又调用了 doService(request,response) 方法,该方法是在DispatcherServlet中具体实现
所以说FrameworkServlet主要有两个作用:
1.创建并初始化Spring容器
2.请求的入口

三、DispatcherServlet

第一个作用是初始化九大组件,就是在上面的FrameworkServlet执行完初始化容器后,就调用 onRefresh ,方法里面只调用了 initStrategies(context) 方法,initStrategies方法才是重点,如下图

每个组件在处理请求时都有可能会用到
第二个作用就是处理请求
请求的入口是doService ,我们看下请求过来的调用链

doService对request设置了一些属性

接着调用doDispatch,doDispatch是DispatcherServlet的核心
我们看代码

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
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
/**
*
* doDispatch中最重要的代码总共有四句(见下面的标签数字)
*
* Handler、HandlerMapping、HandlerAdapter三者的关系:
* Handler:就是我们的控制器Controller中加了@XXXMapping的方法
* HandlerMapping: 用来快速查找Handler
* HandlerAdapter:调用Handler来干活,而且不同Handler需要不同的Adapter
* 这就好比HandlerAdapter是工人,Handler是工具,HandlerMapping是根据加工的需求来选择用
* 什么设备
*/

/**
* 封装Request,如果不是上传请求则直接使用接收到的request
* 如果是上传请求,重新封装成MultipartHttpServletRequest
*/
HttpServletRequest processedRequest = request;
/**
* 处理请求的处理器链
* 包含有处理器Handler和对应的拦截器Interceptor
*/
HandlerExecutionChain mappedHandler = null;
/**
* 是否为上传请求的标记
*/
boolean multipartRequestParsed = false;

/**
* 从request中获取异步请求
*/
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

try {
/**
* View 跟 ViewResolver
* View 是用来展示数据的
* 而ViewResolver是用来查找View的
* 做完请求工作后,需要返回结果,而返回结果就需要模板,
* View就是所需要的模板,ViewResolver就是来选择哪个模板
*
* **/
ModelAndView mv = null;
/**
* 异常声明
* doDispatch()中对异常又两种处理方法:
* 一、如果是处理请求中出现的异常,会捕获并在processDispatchResult中渲染到最后的视图中
* 二、如果是渲染中出现异常,则直接抛出
*/
Exception dispatchException = null;

try {
// 检查是不是上传请求
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);

/** 第一句
* 使用HandlerMapping找到可以干活的Handler
*
* **/
// Determine handler for the current request.
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
// 找不到Handler返回404
noHandlerFound(processedRequest, response);
return;
}

/** 第二句
* 找到合适的HandlerAdapter去让他干活
* **/
// Determine handler adapter for the current request.
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

// 处理GET、HEAD请求的last-modified
// Process last-modified header, if supported by the handler.
/**
* Last-Modified是HTTP头部的一种属性,表示当前请求的资源跟上一次请求的资源是否相同
* 如果相同,返回304并且没有新的实体(body)返回
* 否则返回新的实体内容
*
* 在浏览器第一次请求某一个URL时,服务器端的返回状态会是200,内容是客户端请求的资源,
* 同时有一个Last-Modified的属性标记此文件在服务器端最后被修改的时间。
* 客户端第二次请求此URL时,根据HTTP协议的规定,浏览器会向服务器传送If-Modified-Since报头,询问该时间之后文件是否有被修改过
* 如果服务器端的资源没有变化,则自动返回 HTTP 304(Not Changed.)状态码,内容为空,这样就节省了传输数据量。
* 当服务器端代码发生改变或者重启服务器时,则重新发出资源,
* 返回和第一次请求时类似。从而保证不向客户端重复发出资源,也保证当服务器有变化时,客户端能够得到最新的资源。
*/
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;
}
}

/** 如果有拦截器,就饿执行我们的拦截器,preHandle前置处理**/
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}

/** 第三句
* 让HandlerAdapter开始干活,干完活后返回数据
* **/
// Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

// 如果需要异步处理,则直接返回
/**
* 因为异步处理会重新开启一个线程去执行结果的返回
* 不会占用目前这个线程,所以可以直接返回
*/
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}

// 当view为空时(比如,handler返回类型为void),根据request设置默认view
applyDefaultViewName(processedRequest, mv);
/** 执行了拦截器的后置处理 postHandle**/
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
dispatchException = ex;
}
catch (Throwable err) {
// As of 4.3, we're processing Errors thrown from handler methods as well,
// making them available for @ExceptionHandler methods and other scenarios.
dispatchException = new NestedServletException("Handler dispatch failed", err);
}
/** 第四句
* 将数据处理,通过View展示给用户
* 处理结果,包括处理异常,渲染页面,发出完成通知,触发拦截器的afterCompletion
* **/
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
catch (Throwable err) {
triggerAfterCompletion(processedRequest, response, mappedHandler,
new NestedServletException("Handler processing failed", err));
}
finally {
// 判断是否为异步请求
if (asyncManager.isConcurrentHandlingStarted()) {
// 执行异步的拦截器
// Instead of postHandle and afterCompletion
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
}
else {
// 删除上传请求的资源,不然会产生临时的资源
// Clean up any resources used by a multipart request.
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
}

doDispatch方法主要有四个任务:1.用request找到Handler; 2.根据Handler找到HandlerAdapter; 3.用HandlerAdapter处理Handler 4.调用processDispatchResult方法处理结果(包括异常的处理和View视图的渲染)。除此之外还另外做了许多事情,比如判断是否为上传文件请求,是否带有Last-Modified头部,执行拦截器,是否为异步请求…processDispatchResult方法处理上面doDispatch返回的结果,包括处理异常、渲染页面、触发拦截器的后置处理,处理异常只是处理doDispatch()方法中的异常、渲染页面的异常就抛出。渲染页面的方法调用render