【Tomcat】四.Tomcat处理请求(下)

上一节我们来到了 getAdapter().service(request, response); 这里,接下来需要看一个 连接器 -- Coyote框架 Coyote 的中文意思是 山狗 ,北美的一种狼,我想用这个名字应该是指他非常的迅猛。 它实现了自己的 RequestResponse(不是 servlet 标准),主要用于将 byte数组 翻译成必要的 HTTP信息

一. CoyoteAdapter处理请求

CoyoteAdapter 会将 Socket 接收的 byte数组 包装成 RequestResponse,这是一个 Facade模式,意将解析过程封装起来:

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
public class CoyoteAdapter implements Adapter {


@Override
public void service(org.apache.coyote.Request req, org.apache.coyote.Response res)
throws Exception {

// 构建 Request对象 和 Response对象
Request request = (Request) req.getNote(ADAPTER_NOTES);
Response response = (Response) res.getNote(ADAPTER_NOTES);

if (request == null) {
// Create objects
request = connector.createRequest();
request.setCoyoteRequest(req);
response = connector.createResponse();
response.setCoyoteResponse(res);

// Link objects
request.setResponse(response);
response.setRequest(request);

// Set as notes
req.setNote(ADAPTER_NOTES, request);
res.setNote(ADAPTER_NOTES, response);

// Set query string encoding
req.getParameters().setQueryStringCharset(connector.getURICharset());
}

if (connector.getXpoweredBy()) {
response.addHeader("X-Powered-By", POWERED_BY);
}
// 构建 Request对象 和 Response对象END

boolean async = false;
boolean postParseSuccess = false;

req.getRequestProcessor().setWorkerThreadName(THREAD_NAME.get());

try {
// 解析Request参数,主要为了寻找对应的容器进行处理
postParseSuccess = postParseRequest(req, request, res, response);
if (postParseSuccess) {
//check valves if we support async
request.setAsyncSupported(
connector.getService().getContainer().getPipeline().isAsyncSupported());
// 关键代码!!!!!!:拿到容器直行链的第一个处理器开始处理
// 后续将是一个责任链一直连续下去
connector.getService().getContainer().getPipeline().getFirst().invoke(
request, response);
}
// 异步的请求处理
if (request.isAsync()) {
async = true;
ReadListener readListener = req.getReadListener();
if (readListener != null && request.isFinished()) {
// Possible the all data may have been read during service()
// method so this needs to be checked here
ClassLoader oldCL = null;
try {
oldCL = request.getContext().bind(false, null);
if (req.sendAllDataReadEvent()) {
req.getReadListener().onAllDataRead();
}
} finally {
request.getContext().unbind(false, oldCL);
}
}

Throwable throwable =
(Throwable) request.getAttribute(RequestDispatcher.ERROR_EXCEPTION);

if (!request.isAsyncCompleting() && throwable != null) {
request.getAsyncContextInternal().setErrorState(throwable, true);
}
} else {
// 处理完成数据以后,将响应数据刷新出去
request.finishRequest();
response.finishResponse();
}

} catch (IOException e) {
// Ignore
} finally {
AtomicBoolean error = new AtomicBoolean(false);
res.action(ActionCode.IS_ERROR, error);

if (request.isAsyncCompleting() && error.get()) {
// Connection will be forcibly closed which will prevent
// completion happening at the usual point. Need to trigger
// call to onComplete() here.
res.action(ActionCode.ASYNC_POST_PROCESS, null);
async = false;
}

// 记录请求日志
if (!async && postParseSuccess) {
Context context = request.getContext();
Host host = request.getHost();
long time = System.currentTimeMillis() - req.getStartTime();
if (context != null) {
context.logAccess(request, response, time, false);
} else if (response.isError()) {
if (host != null) {
host.logAccess(request, response, time, false);
} else {
connector.getService().getContainer().logAccess(
request, response, time, false);
}
}
}

req.getRequestProcessor().setWorkerThreadName(null);

// 回收资源
if (!async) {
updateWrapperErrorCount(request, response);
request.recycle();
response.recycle();
}
}
}


}

现在有必要祭出之前那副请求处理图了:


我们现在来到了 Connector 这一步,他会将 RequestResponse 开始传递给 EnginePipeline 进行处理,Pipeline 又会继续调用容器里面的子容器的 Pipeline 逐一处理完成以后,最后来到了我们 webappservice 方法。当 webapp 都执行完成了以后,就会调用到 request.finishRequest()response.finishResponse(); 写出去。

二. CoyoteAdapter写出响应

因为在这里完全可以拿到已经处理完成的 Response 数据,所以也是在这里写出数据的,我打算先看完 请求响应,所以直接先看写出数据。 那么我们上面是 response.finishResponse(); 这个方法来完成响应的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class Response implements HttpServletResponse {  

public void finishResponse() throws IOException {
outputBuffer.close();
}

// 在上面 CoyoteAdapter#service 创建响应的时候,就会创建一个 outputBuffer
// 然后再把这个 outputBuffer 跟 Connector 连起来,就可以将数据通过通道写出去了
public void setConnector(Connector connector) {
if("AJP/1.3".equals(connector.getProtocol())) {
// default size to size of one ajp-packet
outputBuffer = new OutputBuffer(8184);
} else {
outputBuffer = new OutputBuffer();
}
outputStream = new CoyoteOutputStream(outputBuffer);
writer = new CoyoteWriter(outputBuffer);
}
}

而这个 OutputBuffer 是由 Tomcat 提供的,接下来看看 close 做了哪些事情:

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
public class OutputBuffer extends Writer {  
@Override
public void close() throws IOException {

if (closed) {
return;
}
if (suspended) {
return;
}

if (cb.remaining() > 0) {
flushCharBuffer();
}

// 尝试计算ContentLength
if ((!coyoteResponse.isCommitted()) && (coyoteResponse.getContentLengthLong() == -1)
&& !coyoteResponse.getRequest().method().equals("HEAD")) {
if (!coyoteResponse.isCommitted()) {
coyoteResponse.setContentLength(bb.remaining());
}
}

// 如果需要是需要升级请求的话,flush出去
if (coyoteResponse.getStatus() == HttpServletResponse.SC_SWITCHING_PROTOCOLS) {
doFlush(true);
} else {
doFlush(false);
}
closed = true;

// 响应都要关闭了,请求肯定没东西了,所以这时候请求关闭请求的通道
Request req = (Request) coyoteResponse.getRequest().getNote(CoyoteAdapter.ADAPTER_NOTES);
req.inputBuffer.close();

// 又要回到了上面Response对象里边操作
coyoteResponse.action(ActionCode.CLOSE, null);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
public final class Response {
public void action(ActionCode actionCode, Object param) {
if (hook != null) {
if (param == null) {
// ActionCode.CLOSE,hook是之前的 Http11Processor
hook.action(actionCode, this);
} else {
hook.action(actionCode, param);
}
}
}
}
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
public abstract class AbstractProcessor extends AbstractProcessorLight implements ActionHook {

@Override
public final void action(ActionCode actionCode, Object param) {
switch (actionCode) {
// 'Normal' servlet support
case COMMIT: {
if (!response.isCommitted()) {
try {
// 准备响应头
prepareResponse();
} catch (IOException e) {
setErrorState(ErrorState.CLOSE_CONNECTION_NOW, e);
}
}
break;
}
case CLOSE: {
action(ActionCode.COMMIT, null);
try {
finishResponse();
} catch (CloseNowException cne) {
setErrorState(ErrorState.CLOSE_NOW, cne);
} catch (IOException e) {
setErrorState(ErrorState.CLOSE_CONNECTION_NOW, e);
}
break;
}
case ACK: {}
// 省略其他Action动作处理...
}
}

}

case CLOSE 会先递归调用 Commit,然后再调用完成响应的函数。 prepareResponse 包含了验证是否需要写 bodyContent-Type,计算 Content-Length 等等一些必要的 响应头,然后一起写到客户端,代码过长就不放了。 finishResponse

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
public class Http11Processor extends AbstractProcessor {   
@Override
protected final void finishResponse() throws IOException {
outputBuffer.end();
}
}
public class Http11OutputBuffer implements HttpOutputBuffer {
@Override
public void end() throws IOException {
if (responseFinished) {
return;
}

if (lastActiveFilter == -1) {
outputStreamOutputBuffer.end();
} else {
// lastActiveFilter参数在上面的 prepareResponse 会根据响应头
// 来调整,现在被创建了一个 IdentityOutputFilter 也就是将数据写出去
// 其他类型的还有ChunkedOutputFilter、GzipOutputFilter、VoidOutputFilter
// 分别处理 分批、压缩、以及没有响应体的。
activeFilters[lastActiveFilter].end();
}

responseFinished = true;
}
}

那现在就需要来观察 IdentityOutputFilterend 函数,然而这个 end 函数会一步一步通过 代理 传递到对应的 Socketend 函数来完成:

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
public class IdentityOutputFilter implements OutputFilter {

@Override
public void end() throws IOException {
buffer.end();
}

}

protected class SocketOutputBuffer implements HttpOutputBuffer {

@Override
public void end() throws IOException {
socketWrapper.flush(true);
}

}

public static class NioSocketWrapper extends SocketWrapperBase<NioChannel> {

public boolean flush(boolean block) throws IOException {
boolean result = false;
if (block) {
// A blocking flush will always empty the buffer.
flushBlocking();
} else {
result = flushNonBlocking();
}

return result;
}
protected void flushBlocking() throws IOException {
doWrite(true);

if (!nonBlockingWriteBuffer.isEmpty()) {
nonBlockingWriteBuffer.write(this, true);

if (!socketBufferHandler.isWriteBufferEmpty()) {
doWrite(true);
}
}

}
protected void doWrite(boolean block) throws IOException {
socketBufferHandler.configureWriteBufferForRead();
doWrite(block, socketBufferHandler.getWriteBuffer());
}
// 上面三个方法在SocketWrapperBase中 为了阅读方便就放一起了

@Override
protected void doWrite(boolean block, ByteBuffer from) throws IOException {
long writeTimeout = getWriteTimeout();
Selector selector = null;
try {
selector = pool.get();
} catch (IOException x) {

}
try {
// 通过Socket定位到对应的通道,然后将数据写到通道里面
pool.write(from, getSocket(), selector, writeTimeout, block);
if (block) {
// Make sure we are flushed
do {
// 刷新出去,刷新成功返回true就停止循环
if (getSocket().flush(true, selector, writeTimeout)) {
break;
}
} while (true);
}
updateLastWrite();
} finally {
if (selector != null) {
pool.put(selector);
}
}

}
}

三.业务数据处理链

业务数据的处理主要发生在上面提到过的 CoyoteAdapter 中,我重新贴一下代码:

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
public class CoyoteAdapter implements Adapter {


@Override
public void service(org.apache.coyote.Request req, org.apache.coyote.Response res)
throws Exception {

// 构建 Request对象 和 Response对象
Request request = (Request) req.getNote(ADAPTER_NOTES);
Response response = (Response) res.getNote(ADAPTER_NOTES);

if (request == null) {
// Create objects
request = connector.createRequest();
request.setCoyoteRequest(req);
response = connector.createResponse();
response.setCoyoteResponse(res);

// Link objects
request.setResponse(response);
response.setRequest(request);

// Set as notes
req.setNote(ADAPTER_NOTES, request);
res.setNote(ADAPTER_NOTES, response);

// Set query string encoding
req.getParameters().setQueryStringCharset(connector.getURICharset());
}

if (connector.getXpoweredBy()) {
response.addHeader("X-Powered-By", POWERED_BY);
}
// 构建 Request对象 和 Response对象END

boolean async = false;
boolean postParseSuccess = false;

req.getRequestProcessor().setWorkerThreadName(THREAD_NAME.get());

try {
// 解析Request参数,主要为了寻找对应的容器进行处理
postParseSuccess = postParseRequest(req, request, res, response);
if (postParseSuccess) {
//check valves if we support async
request.setAsyncSupported(
connector.getService().getContainer().getPipeline().isAsyncSupported());
// 关键代码!!!!!!:拿到容器直行链的第一个处理器开始处理
// 后续将是一个责任链一直连续下去
connector.getService().getContainer().getPipeline().getFirst().invoke(
request, response);
}
// 异步的请求处理
if (request.isAsync()) {
async = true;
ReadListener readListener = req.getReadListener();
if (readListener != null && request.isFinished()) {
// Possible the all data may have been read during service()
// method so this needs to be checked here
ClassLoader oldCL = null;
try {
oldCL = request.getContext().bind(false, null);
if (req.sendAllDataReadEvent()) {
req.getReadListener().onAllDataRead();
}
} finally {
request.getContext().unbind(false, oldCL);
}
}

Throwable throwable =
(Throwable) request.getAttribute(RequestDispatcher.ERROR_EXCEPTION);

if (!request.isAsyncCompleting() && throwable != null) {
request.getAsyncContextInternal().setErrorState(throwable, true);
}
} else {
// 处理完成数据以后,将响应数据刷新出去
request.finishRequest();
response.finishResponse();
}

} catch (IOException e) {
// Ignore
} finally {
AtomicBoolean error = new AtomicBoolean(false);
res.action(ActionCode.IS_ERROR, error);

if (request.isAsyncCompleting() && error.get()) {
// Connection will be forcibly closed which will prevent
// completion happening at the usual point. Need to trigger
// call to onComplete() here.
res.action(ActionCode.ASYNC_POST_PROCESS, null);
async = false;
}

// 记录请求日志
if (!async && postParseSuccess) {
Context context = request.getContext();
Host host = request.getHost();
long time = System.currentTimeMillis() - req.getStartTime();
if (context != null) {
context.logAccess(request, response, time, false);
} else if (response.isError()) {
if (host != null) {
host.logAccess(request, response, time, false);
} else {
connector.getService().getContainer().logAccess(
request, response, time, false);
}
}
}

req.getRequestProcessor().setWorkerThreadName(null);

// 回收资源
if (!async) {
updateWrapperErrorCount(request, response);
request.recycle();
response.recycle();
}
}
}


}

connector.getService().getContainer().getPipeline().getFirst().invoke(request, response); 就是调用处理链来处理请求和写响应数据的关键:


connector.getService().getContainer() 就是拿到了 Engine 对象,再通过 getPipeline().getFirst() 拿到第一个 Pipeline 处理器,开始进行调用,也就是图中的 StandardEngineValve,图中还有 ValveAValveB 表示我们可以根据自己的需求进行 Pipeline 的组装:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
final class StandardEngineValve extends ValveBase {

@Override
public final void invoke(Request request, Response response)
throws IOException, ServletException {

// 找到当前请求需要使用到的 Host 对象,如果没有找到,则表示请求不到
Host host = request.getHost();
if (host == null) {
response.sendError
(HttpServletResponse.SC_BAD_REQUEST,
sm.getString("standardEngine.noHost",
request.getServerName()));
return;
}
if (request.isAsyncSupported()) {
request.setAsyncSupported(host.getPipeline().isAsyncSupported());
}

// 将请求交给 Host 进行处理
host.getPipeline().getFirst().invoke(request, response);

}
}

那我使用的是默认的配置,HostPipeline 第一个即是 AccessLogValve 来处理请求的记录信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public abstract class AbstractAccessLogValve extends ValveBase implements AccessLog {
// 当前this=`AccessLogValue`,集成这个抽象类
@Override
public void invoke(Request request, Response response) throws IOException,
ServletException {
if (tlsAttributeRequired) {
// 如果开启了TLS,则需要先把属性缓存起来
request.getAttribute(Globals.CERTIFICATES_ATTR);
}
// 处理读取Request中,Socket包含的远程客户端的地址,目前是HostCache进行处理
for (CachedElement element : cachedElements) {
element.cache(request);
}
// Next是ErrorReportValve进行处理
getNext().invoke(request, response);
}

}

然后交给 ErrorReportValve 处理,他是先将 Request 继续传递下去,如果 Response 响应的是错误的,那么会根据需求渲染错误的页面,也就是我们经常看到的 Tomcat 的错误页面:

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
public class ErrorReportValve extends ValveBase {
@Override
public void invoke(Request request, Response response) throws IOException, ServletException {

// Perform the request
getNext().invoke(request, response);

// 下面是处理相应错误的时候,需要做的事情
if (response.isCommitted()) {
if (response.setErrorReported()) {
try {
response.flushBuffer();
} catch (Throwable t) {
ExceptionUtils.handleThrowable(t);
}
response.getCoyoteResponse().action(ActionCode.CLOSE_NOW,
request.getAttribute(RequestDispatcher.ERROR_EXCEPTION));
}
return;
}

Throwable throwable = (Throwable) request.getAttribute(RequestDispatcher.ERROR_EXCEPTION);
if (request.isAsync() && !request.isAsyncCompleting()) {
return;
}

if (throwable != null && !response.isError()) {
response.reset();
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
}

response.setSuspended(false);

try {
report(request, response, throwable);
} catch (Throwable tt) {
ExceptionUtils.handleThrowable(tt);
}
}
}

ErrorReportValve 的接下来一个是 StandardHostValve

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
final class StandardHostValve extends ValveBase {  
@Override
public final void invoke(Request request, Response response)
throws IOException, ServletException {

// Select the Context to be used for this Request
Context context = request.getContext();
if (context == null) {
return;
}

if (request.isAsyncSupported()) {
request.setAsyncSupported(context.getPipeline().isAsyncSupported());
}

boolean asyncAtStart = request.isAsync();

try {
context.bind(Globals.IS_SECURITY_ENABLED, MY_CLASSLOADER);

if (!asyncAtStart && !context.fireRequestInitEvent(request.getRequest())) {
return;
}

// 查找对应的Context进行处理
try {
if (!response.isErrorReportRequired()) {
context.getPipeline().getFirst().invoke(request, response);
}
} catch (Throwable t) {
ExceptionUtils.handleThrowable(t);
container.getLogger().error("Exception Processing " + request.getRequestURI(), t);
// 处理失败,指的是查找我们容器的过程中的失败,则会抛出异常,渲染页面
// 而如果我们的webapp处理失败了,没有做统一的监听返回响应处理的话,也算在这里
// 一般建议我们的项目可以监听错误从而表示项目是正常运行的只不过是业务错误,返回业务错误信息即可
if (!response.isErrorReportRequired()) {
request.setAttribute(RequestDispatcher.ERROR_EXCEPTION, t);
throwable(request, response, t);
}
}

// 处理已经请求完成了,现在可以处理Response了,例如要刷出数据等工作
response.setSuspended(false);

Throwable t = (Throwable) request.getAttribute(RequestDispatcher.ERROR_EXCEPTION);

if (!context.getState().isAvailable()) {
return;
}

// 如果相应出现了错误,根据需要,要渲染页面或者是要返回错误编码
if (response.isErrorReportRequired()) {
// 判断Channel通道是否正常,如果非正常的,则不会继续收集错误
AtomicBoolean result = new AtomicBoolean(false);
response.getCoyoteResponse().action(ActionCode.IS_IO_ALLOWED, result);
if (result.get()) {
if (t != null) {
throwable(request, response, t);
} else {
status(request, response);
}
}
}

// Request已经完成他的使命,触发Request的销毁事件
if (!request.isAsync() && !asyncAtStart) {
context.fireRequestDestroyEvent(request.getRequest());
}
} finally {
// Access a session (if present) to update last accessed time, based
// on a strict interpretation of the specification
if (ACCESS_SESSION) {
request.getSession(false);
}

context.unbind(Globals.IS_SECURITY_ENABLED, MY_CLASSLOADER);
}
}
}

Host 有了,接下来就是 ContextPipeline 了吧,不过默认第一个是 AuthenticatorValve 但是我们没有配置什么鉴权的请求,所以我打算跳过他,接下来就是:

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
final class StandardContextValve extends ValveBase {    
@Override
public final void invoke(Request request, Response response)
throws IOException, ServletException {

// 保护敏感目录不被请求
MessageBytes requestPathMB = request.getRequestPathMB();
if ((requestPathMB.startsWithIgnoreCase("/META-INF/", 0))
(requestPathMB.equalsIgnoreCase("/META-INF"))
(requestPathMB.startsWithIgnoreCase("/WEB-INF/", 0))
(requestPathMB.equalsIgnoreCase("/WEB-INF"))) {
response.sendError(HttpServletResponse.SC_NOT_FOUND);
return;
}

// 找到Servlet
Wrapper wrapper = request.getWrapper();
if (wrapper == null wrapper.isUnavailable()) {
response.sendError(HttpServletResponse.SC_NOT_FOUND);
return;
}

// 响应100-continue,告诉客户端你可以继续发送消息了
try {
response.sendAcknowledgement();
} catch (IOException ioe) {
container.getLogger().error(sm.getString(
"standardContextValve.acknowledgeException"), ioe);
request.setAttribute(RequestDispatcher.ERROR_EXCEPTION, ioe);
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
return;
}

if (request.isAsyncSupported()) {
request.setAsyncSupported(wrapper.getPipeline().isAsyncSupported());
}
// 拿到Servlet,开始进行调用,不过在这之前,还有个Filter要用到
wrapper.getPipeline().getFirst().invoke(request, response);
}
}

StandardWrapperValve 基本可以当成表示我们的 webapp 了:

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
final class StandardWrapperValve extends ValveBase {

@Override
public final void invoke(Request request, Response response)
throws IOException, ServletException {

// Initialize local variables we may need
boolean unavailable = false;
Throwable throwable = null;
// This should be a Request attribute...
long t1=System.currentTimeMillis();
requestCount.incrementAndGet();
StandardWrapper wrapper = (StandardWrapper) getContainer();
Servlet servlet = null;
Context context = (Context) wrapper.getParent();

// 保证当前应用是否被停止,在manage页面上管理
if (!context.getState().isAvailable()) {
response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE,
sm.getString("standardContext.isUnavailable"));
unavailable = true;
}

// 保证servlet可用
if (!unavailable && wrapper.isUnavailable()) {
container.getLogger().info(sm.getString("standardWrapper.isUnavailable",
wrapper.getName()));
long available = wrapper.getAvailable();
if ((available > 0L) && (available < Long.MAX_VALUE)) {
response.setDateHeader("Retry-After", available);
response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE,
sm.getString("standardWrapper.isUnavailable",
wrapper.getName()));
} else if (available == Long.MAX_VALUE) {
response.sendError(HttpServletResponse.SC_NOT_FOUND,
sm.getString("standardWrapper.notFound",
wrapper.getName()));
}
unavailable = true;
}

// 申请需要用到的servlet
try {
if (!unavailable) {
servlet = wrapper.allocate();
}
} catch (UnavailableException e) {
// 省略异常处理代码...
}

MessageBytes requestPathMB = request.getRequestPathMB();
DispatcherType dispatcherType = DispatcherType.REQUEST;
if (request.getDispatcherType()==DispatcherType.ASYNC) dispatcherType = DispatcherType.ASYNC;
request.setAttribute(Globals.DISPATCHER_TYPE_ATTR,dispatcherType);
request.setAttribute(Globals.DISPATCHER_REQUEST_PATH_ATTR,
requestPathMB);
// 创建webapp处理链,包含过滤器filter、servlet等
ApplicationFilterChain filterChain =
ApplicationFilterFactory.createFilterChain(request, wrapper, servlet);

try {
if ((servlet != null) && (filterChain != null)) {
// Swallow output if needed
if (context.getSwallowOutput()) {
try {
SystemLogHandler.startCapture();
if (request.isAsyncDispatching()) {
request.getAsyncContextInternal().doInternalDispatch();
} else {
filterChain.doFilter(request.getRequest(),
response.getResponse());
}
} finally {
String log = SystemLogHandler.stopCapture();
if (log != null && log.length() > 0) {
context.getLogger().info(log);
}
}
} else {
if (request.isAsyncDispatching()) {
request.getAsyncContextInternal().doInternalDispatch();
} else {
// 重点进入的代码,调用处理链进行请求响应的处理
// 并且在此时,Connector的Request和Response被转换为符合Servlet规范的对象
// 在Tomcat里被包装成RequestFacade和ResponseFacade
filterChain.doFilter
(request.getRequest(), response.getResponse());
}
}

}
} catch (ClientAbortException CloseNowException e) {
// 省略调用webapp可能发生的错误异常处理代码......
} finally {
// 释放资源
if (filterChain != null) {
filterChain.release();
}

// 释放servlet对象代码
try {
if (servlet != null) {
wrapper.deallocate(servlet);
}
} catch (Throwable e) {
ExceptionUtils.handleThrowable(e);
container.getLogger().error(sm.getString("standardWrapper.deallocateException",
wrapper.getName()), e);
if (throwable == null) {
throwable = e;
exception(request, response, e);
}
}

// If this servlet has been marked permanently unavailable,
// unload it and release this instance
try {
if ((servlet != null) &&
(wrapper.getAvailable() == Long.MAX_VALUE)) {
wrapper.unload();
}
} catch (Throwable e) {
ExceptionUtils.handleThrowable(e);
container.getLogger().error(sm.getString("standardWrapper.unloadException",
wrapper.getName()), e);
if (throwable == null) {
exception(request, response, e);
}
}
long t2=System.currentTimeMillis();

long time=t2-t1;
processingTime += time;
if( time > maxTime) maxTime=time;
if( time < minTime) minTime=time;
}
}

}

然后,通过了一个 Filter 之后,就可以进入我们 webappServlet 进行处理了,反正我们通常是使用 SpringMVCServlet 通常都是 DispatchServlet

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
public final class ApplicationFilterChain implements FilterChain {

@Override
public void doFilter(ServletRequest request, ServletResponse response)
throws IOException, ServletException {
// 没有开启安全策略
if( Globals.IS_SECURITY_ENABLED ) {
final ServletRequest req = request;
final ServletResponse res = response;
try {
java.security.AccessController.doPrivileged(
new java.security.PrivilegedExceptionAction<Void>() {
@Override
public Void run()
throws ServletException, IOException {
internalDoFilter(req,res);
return null;
}
}
);
} catch( PrivilegedActionException pe) {
Exception e = pe.getException();
if (e instanceof ServletException)
throw (ServletException) e;
else if (e instanceof IOException)
throw (IOException) e;
else if (e instanceof RuntimeException)
throw (RuntimeException) e;
else
throw new ServletException(e.getMessage(), e);
}
} else {
// 直接调用
internalDoFilter(request,response);
}
}

private void internalDoFilter(ServletRequest request,
ServletResponse response)
throws IOException, ServletException {

// 如果存在过滤器,默认是有一个WsServerContainer,则调用过滤器的方法
if (pos < n) {
// 在下一个filter又会调用回来,但是此时 pos = n 了,所以不会再走一次
ApplicationFilterConfig filterConfig = filters[pos++];
try {
// WsServerContainer是当前的Filter
Filter filter = filterConfig.getFilter();

if (request.isAsyncSupported() && "false".equalsIgnoreCase(
filterConfig.getFilterDef().getAsyncSupported())) {
request.setAttribute(Globals.ASYNC_SUPPORTED_ATTR, Boolean.FALSE);
}
if( Globals.IS_SECURITY_ENABLED ) {
final ServletRequest req = request;
final ServletResponse res = response;
Principal principal =
((HttpServletRequest) req).getUserPrincipal();

Object[] args = new Object[]{req, res, this};
SecurityUtil.doAsPrivilege ("doFilter", filter, classType, args, principal);
} else {
filter.doFilter(request, response, this);
}
} catch (IOException ServletException RuntimeException e) {
throw e;
} catch (Throwable e) {
e = ExceptionUtils.unwrapInvocationTargetException(e);
ExceptionUtils.handleThrowable(e);
throw new ServletException(sm.getString("filterChain.filter"), e);
}
return;
}

// 过滤器链处理完成,接下来交给servlet的service方法处理
try {
if (ApplicationDispatcher.WRAP_SAME_OBJECT) {
lastServicedRequest.set(request);
lastServicedResponse.set(response);
}

if (request.isAsyncSupported() && !servletSupportsAsync) {
request.setAttribute(Globals.ASYNC_SUPPORTED_ATTR,
Boolean.FALSE);
}
// Use potentially wrapped request from this point
if ((request instanceof HttpServletRequest) &&
(response instanceof HttpServletResponse) &&
Globals.IS_SECURITY_ENABLED ) {
final ServletRequest req = request;
final ServletResponse res = response;
Principal principal =
((HttpServletRequest) req).getUserPrincipal();
Object[] args = new Object[]{req, res};
SecurityUtil.doAsPrivilege("service",
servlet,
classTypeUsedInService,
args,
principal);
} else {
// MyServlet#service,此时是MyServlet,我在里面写了数据到Response,然后交给Connector写出去
// 由于类加载器的隔离,在这里并不知道MyServlet的内容,只管调用即可
servlet.service(request, response);
}
} catch (IOException ServletException RuntimeException e) {
throw e;
} catch (Throwable e) {
e = ExceptionUtils.unwrapInvocationTargetException(e);
ExceptionUtils.handleThrowable(e);
throw new ServletException(sm.getString("filterChain.servlet"), e);
} finally {
if (ApplicationDispatcher.WRAP_SAME_OBJECT) {
lastServicedRequest.set(null);
lastServicedResponse.set(null);
}
}
}

}

那最后完善下那幅请求图: