当Tomcat NioEndpoint中的poller线程监测到一个待处理的socket NIO事件时,它会将该事件委托给SocketProcessor在一个线程池或者当前线程完成相应的处理逻辑。
NioEndpoint$Poller.run()
=> processkey()
=> NioEndpoint父类AbstractEndpoint.processSocket()
=> createSocketProcessor() // 创建SocketProcessor,随后在Worker线程池上执行其逻辑
/**
* AbstractEndpoint的方法processSocket()
* Process the given SocketWrapper with the given status. Used to trigger
* processing as if the Poller (for those endpoints that have one)
* selected the socket.
*
* @param socketWrapper The socket wrapper to process
* @param event The socket event to be processed
* @param dispatch Should the processing be performed on a new
* container thread
*
* @return if processing was triggered successfully
*/
public boolean processSocket(SocketWrapperBase<S> socketWrapper,
SocketEvent event, boolean dispatch) {
try {
if (socketWrapper == null) {
return false;
}
// 尝试循环利用之前回收的SocketProcessor对象,如果没有可回收利用的则
// 创建新的SocketProcessor对象
SocketProcessorBase<S> sc = processorCache.pop();
if (sc == null) {
// 创建新的SocketProcessor对象
sc = createSocketProcessor(socketWrapper, event);
} else {
// 循环利用回收的SocketProcessor对象
sc.reset(socketWrapper, event);
}
// 找到Worker线程池或者Worker线程
Executor executor = getExecutor();
if (dispatch && executor != null) {
// 如果Worker线程池被设置并且被要求分发:dispatch==true,
// 则在Worker线程池上执行刚刚封装的SocketProcessor的设定逻辑
executor.execute(sc);
} else {
// 否则在当前线程上直接执行刚刚封装的SocketProcessor的设定逻辑
sc.run();
}
} catch (RejectedExecutionException ree) {
getLog().warn(sm.getString("endpoint.executor.fail", socketWrapper) , ree);
return false;
} catch (Throwable t) {
ExceptionUtils.handleThrowable(t);
// This means we got an OOM or similar creating a thread, or that
// the pool and its queue are full
getLog().error(sm.getString("endpoint.process.fail"), t);
return false;
}
return true;
}
// NioEndpoint重写了父类AbstractEndpoint的方法createSocketProcessor
@Override
protected SocketProcessorBase<NioChannel> createSocketProcessor(
SocketWrapperBase<NioChannel> socketWrapper, SocketEvent event) {
return new SocketProcessor(socketWrapper, event);
}
protected class SocketProcessor extends SocketProcessorBase<NioChannel> {
public SocketProcessor(SocketWrapperBase<NioChannel> socketWrapper, SocketEvent event) {
super(socketWrapper, event);
}
@Override
protected void doRun() {
// 该方法将会执行于 tomcat 的 worker 线程中,比如 : http-nio-8080-exec-1
// 获取待处理的客户端请求
NioChannel socket = socketWrapper.getSocket();
SelectionKey key = socket.getIOChannel().keyFor(socket.getPoller().getSelector());
try {
// 这里的 handshake 是用来处理 https 的握手过程的,
// 如果是 http 不需要该握手阶段,下面会将该标志设置为 0, 表示握手已经完成
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());
// The handshake process reads/writes from/to the
// socket. status may therefore be OPEN_WRITE once
// the handshake completes. However, the handshake
// happens when the socket is opened so the status
// must always be OPEN_READ after it completes. It
// is OK to always set this as it is only used if
// the handshake completes.
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) {
// 默认是读事件处理
// 这里的getHandler()返回AbstractProtocol.ConnectionHandler,
// 在Http11NioProtocol对象构造期间被创建并设置到当前NioEndpoint对象
state = getHandler().process(socketWrapper, SocketEvent.OPEN_READ);
} else {
// 响应指定事件处理
// 这里的getHandler()返回AbstractProtocol.ConnectionHandler,
// 在Http11NioProtocol对象构造期间被创建并设置到当前NioEndpoint对象
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();
}
} catch (CancelledKeyException cx) {
socket.getPoller().cancelledKey(key);
} catch (VirtualMachineError vme) {
ExceptionUtils.handleThrowable(vme);
} catch (Throwable t) {
log.error("", t);
socket.getPoller().cancelledKey(key);
} finally {
socketWrapper = null;
event = null;
//return to cache
if (running && !paused) {
processorCache.push(this);
}
}
}
}
public abstract class SocketProcessorBase<S> implements Runnable {
protected SocketWrapperBase<S> socketWrapper;
protected SocketEvent event;
public SocketProcessorBase(SocketWrapperBase<S> socketWrapper, SocketEvent event) {
reset(socketWrapper, event);
}
public void reset(SocketWrapperBase<S> socketWrapper, SocketEvent event) {
Objects.requireNonNull(event);
this.socketWrapper = socketWrapper;
this.event = event;
}
@Override
public final void run() {
synchronized (socketWrapper) {
// It is possible that processing may be triggered for read and
// write at the same time. The sync above makes sure that processing
// does not occur in parallel. The test below ensures that if the
// first event to be processed results in the socket being closed,
// the subsequent events are not processed.
if (socketWrapper.isClosed()) {
return;
}
doRun();
}
}
protected abstract void doRun();
}