Tomcat异步Servlet实现分析——异步结束
上篇我们说了tomcat如何开启异步上下文,这篇我们看tomcat如何结束异步。
源码
tomcat结束可以使用两种方式:complete和dispatch。complete用来告诉tomcat,异步结束了。
先看这种方式:
case ASYNC_COMPLETE: {
clearDispatches();
if (asyncStateMachine.asyncComplete()) {
processSocketEvent(SocketEvent.OPEN_READ, true);
}
break;
}
先看asyncStateMachine.asyncComplete,这个方法主要是由状态机去推进状态:
if (!ContainerThreadMarker.isContainerThread() && state == AsyncState.STARTING) {
state = AsyncState.COMPLETE_PENDING;
return false;
} else {
return doComplete();
}
第二步比较重要:
SocketWrapperBase<?> socketWrapper = getSocketWrapper();
if (socketWrapper != null) {
socketWrapper.processSocket(event, dispatch);
}
追进去:endpoint.processSocket(this, socketStatus, dispatch);,继续追进去:
//...
if (socketWrapper == null) {
return false;
}
SocketProcessorBase<S> sc = processorCache.pop();
if (sc == null) {
sc = createSocketProcessor(socketWrapper, event);
} else {
sc.reset(socketWrapper, event);
}
Executor executor = getExecutor();
if (dispatch && executor != null) {
executor.execute(sc);
} else {
sc.run();
}
//...
return true;
我们先知道一下,Tomcat在8.5和9.0版本已经完全摒弃了BIO的方式,默认使用NIO,这个endpoint的实例是NioEndpoint,先是获取一个SocketProcessorBase,这个实例是SocketProcessor(NioEndpoint中的一个内部类),这也是一个工作线程,做了什么呢?
相当于重新开启一个工作线程,这个工作线程带着SocketWrapper,又来一遍容器的流程,而这一遍的流程,因为Servlet已经处理过,所以会略过servlet的执行直接将后续的处理走完,包括最后response的收尾,对象的清空等等,我们可以看一下这个SocketProcessor的doRun方法(片段):
int handshake = -1;
try {
if (key != null) {
if (socket.isHandshakeComplete()) {
// No TLS handshaking required. Let the handler
// process this socket / event combination.
handshake = 0;
} else if (event == SocketEvent.STOP || event == SocketEvent.DISCONNECT ||
event == SocketEvent.ERROR) {
// Unable to complete the TLS handshake. Treat it as
// if the handshake failed.
handshake = -1;
} else {
handshake = socket.handshake(key.isReadable(), key.isWritable());
event = SocketEvent.OPEN_READ;
}
}
} catch (IOException x) {
handshake = -1;
if (log.isDebugEnabled()) log.debug("Error during SSL handshake",x);
} catch (CancelledKeyException ckx) {
handshake = -1;
}
if (handshake == 0) {
SocketState state = SocketState.OPEN;
// Process the request from this socket
if (event == null) {
state = getHandler().process(socketWrapper, SocketEvent.OPEN_READ);
} else {
state = getHandler().process(socketWrapper, event);
}
if (state == SocketState.CLOSED) {
close(socket, key);
}
} else if (handshake == -1 ) {
close(socket, key);
} else if (handshake == SelectionKey.OP_READ){
socketWrapper.registerReadInterest();
} else if (handshake == SelectionKey.OP_WRITE){
socketWrapper.registerWriteInterest();
}
这里我们可以看到,这里面是一些握手操作,成功之后执行服务。这个state = getHandler().process(socketWrapper, event);会最终执行一个服务。
异步的情况下,之前我们说过了,不会重复跑一次servlet的,而是
Tomcat异步Servlet实现分析——开启异步上下文