上一篇說到了Tomcat的啟動流程于个,那么請求處理的流程是如何完成的呢模她?
Connector接收請求
Connector是請求接收器,通過設置的協(xié)議處理器處理請求缭保,以默認的Http11NioProtocol協(xié)議為例遥缕,Http11NioProtocol構(gòu)造時創(chuàng)建了NioEndpoint侥祭,用來處理網(wǎng)絡請求:
public Http11NioProtocol() {
super(new NioEndpoint());
}
Connector啟動時,啟動了protocolHandler(Http11NioProtocol), protocolHandler啟動的時候又對endpoint進行了啟動齐婴,NioEndpoint啟動過程中綁定了本地端口并在Acceptor線程中監(jiān)聽網(wǎng)絡連接(詳情可見Tomcat啟動流程)油猫,所以Tomcat接收網(wǎng)絡請求的起點是從Accetpor線程開始的。
Acceptor中會循環(huán)阻塞調(diào)用serverSock.accept()來監(jiān)聽請求:
......
try {
// Accept the next incoming connection from the server
// socket
socket = endpoint.serverSocketAccept();
} catch (Exception ioe) {
// We didn't get a socket
endpoint.countDownConnection();
if (endpoint.isRunning()) {
// Introduce delay if necessary
errorDelay = handleExceptionWithDelay(errorDelay);
// re-throw
throw ioe;
} else {
break;
}
}
// Successful accept, reset the error delay
errorDelay = 0;
// Configure the socket
if (endpoint.isRunning() && !endpoint.isPaused()) {
// setSocketOptions() will hand the socket off to
// an appropriate processor if successful
if (!endpoint.setSocketOptions(socket)) {
endpoint.closeSocket(socket);
}
} else {
endpoint.destroySocket(socket);
}
......
接收到請求后尔店,通過setSocketOptions來處理請求:
protected boolean setSocketOptions(SocketChannel socket) {
NioSocketWrapper socketWrapper = null;
try {
// Allocate channel and wrapper
NioChannel channel = null;
if (nioChannels != null) {
channel = nioChannels.pop();
}
if (channel == null) {
SocketBufferHandler bufhandler = new SocketBufferHandler(
socketProperties.getAppReadBufSize(),
socketProperties.getAppWriteBufSize(),
socketProperties.getDirectBuffer());
if (isSSLEnabled()) {
channel = new SecureNioChannel(bufhandler, selectorPool, this);
} else {
channel = new NioChannel(bufhandler);
}
}
NioSocketWrapper newWrapper = new NioSocketWrapper(channel, this);
channel.reset(socket, newWrapper);
connections.put(socket, newWrapper);
socketWrapper = newWrapper;
// Set socket properties
// Disable blocking, polling will be used
socket.configureBlocking(false);
socketProperties.setProperties(socket.socket());
socketWrapper.setReadTimeout(getConnectionTimeout());
socketWrapper.setWriteTimeout(getConnectionTimeout());
socketWrapper.setKeepAliveLeft(NioEndpoint.this.getMaxKeepAliveRequests());
socketWrapper.setSecure(isSSLEnabled());
poller.register(channel, socketWrapper);
return true;
} catch (Throwable t) {
ExceptionUtils.handleThrowable(t);
try {
log.error(sm.getString("endpoint.socketOptionsError"), t);
} catch (Throwable tt) {
ExceptionUtils.handleThrowable(tt);
}
if (socketWrapper == null) {
destroySocket(socket);
}
}
// Tell to close the socket if needed
return false;
}
代碼比較長眨攘,最關鍵的代碼是poller.register(channel, socketWrapper)主慰,將請求進來的socket包裝后注冊到poller中等待讀寫事件嚣州,這個地方的socket是非阻塞的鲫售,即可以用一個poller線程處理大量的請求連接,提高系統(tǒng)吞吐量该肴。
接下來來到Poller類:
public void register(final NioChannel socket, final NioSocketWrapper socketWrapper) {
socketWrapper.interestOps(SelectionKey.OP_READ);//this is what OP_REGISTER turns into.
PollerEvent r = null;
if (eventCache != null) {
r = eventCache.pop();
}
if (r == null) {
r = new PollerEvent(socket, OP_REGISTER);
} else {
r.reset(socket, OP_REGISTER);
}
addEvent(r);
}
Poller線程run方法:
@Override
public void run() {
// Loop until destroy() is called
while (true) {
boolean hasEvents = false;
try {
if (!close) {
hasEvents = events();
...
keyCount = selector.select(selectorTimeout);
...
wakeupCounter.set(0);
}
...
} catch (Throwable x) {
ExceptionUtils.handleThrowable(x);
log.error(sm.getString("endpoint.nio.selectorLoopError"), x);
continue;
}
// Either we timed out or we woke up, process events first
if (keyCount == 0) {
hasEvents = (hasEvents | events());
}
Iterator<SelectionKey> iterator =
keyCount > 0 ? selector.selectedKeys().iterator() : null;
// Walk through the collection of ready keys and dispatch
// any active event.
while (iterator != null && iterator.hasNext()) {
SelectionKey sk = iterator.next();
NioSocketWrapper socketWrapper = (NioSocketWrapper) sk.attachment();
processKey(sk, socketWrapper);
}
代碼進行了一些刪減情竹,只保留了主要流程:
1.Poller注冊socket
Poller將連接上的socket設置interestOps(SelectionKey.OP_READ),包裝成PollerEvent匀哄,interestOps為OP_REGISTER秦效,放入隊列中。
2.Poller線程從隊列中取事件涎嚼,執(zhí)行run方法:
if (interestOps == OP_REGISTER) {
try {
socket.getIOChannel().register(socket.getSocketWrapper().getPoller().getSelector(), SelectionKey.OP_READ, socket.getSocketWrapper());
} catch (Exception x) {
log.error(sm.getString("endpoint.nio.registerFail"), x);
}
}
將socket注冊到Poller的Selector中阱州,ops為SelectionKey.OP_READ,等待對端發(fā)送數(shù)據(jù)法梯。
3.然后在socket有數(shù)據(jù)可讀時苔货,通過processKey(sk, socketWrapper)來進行處理。繼續(xù)跟進processKey立哑,最終將socket封裝成socketProcessor提交到Executor處理夜惭。
public boolean processSocket(SocketWrapperBase<S> socketWrapper,
SocketEvent event, boolean dispatch) {
try {
if (socketWrapper == null) {
return false;
}
SocketProcessorBase<S> sc = null;
if (processorCache != null) {
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();
}
......
SocketProcessor實現(xiàn)了Runnable接口,在線程池中執(zhí)行SocketProcessor.doRun,忽略可能的TLS握手到流程铛绰,將通過連接處理器ConnectionHandler來處理請求:
getHandler().process(socketWrapper, SocketEvent.OPEN_READ);
ConnectHandler又通過Http11Processor來處理
if (processor == null) {
processor = getProtocol().createProcessor();
register(processor);
}
...
// Associate the processor with the connection
wrapper.setCurrentProcessor(processor);
SocketState state = SocketState.CLOSED;
do {
state = processor.process(wrapper, status);
Http11Processor中會根據(jù)Http協(xié)議來解析數(shù)據(jù)诈茧,封裝成request、response模型捂掰,并通過適配器轉(zhuǎn)給Container敢会,然后Connector的任務就完成了,接下來的操作由Container來進行这嚣。
getAdapter().service(request, response);
Adapter的處理
Connect的主要任務是接收請求鸥昏,并在有數(shù)據(jù)讀寫時在線程池中根據(jù)使用的協(xié)議來解析數(shù)據(jù)并封裝成request、response疤苹,然后交給Adapter來處理互广。
Adapter的實現(xiàn)類是CoyoteAdapter,顧名思義是一個適配器卧土,將Connector連接器讀取的數(shù)據(jù)適配到Container容器來處理惫皱。
Adapter主要有兩個任務map和轉(zhuǎn)發(fā)。
map在postParseRequest方法中進行:
connector.getService().getMapper().map(serverName, decodedURI,
version, request.getMappingData());
根據(jù)請求到uri找到目標Host尤莺、Context旅敷、Wrapper。
Mapper對象存在service中颤霎,通過MapperListener來監(jiān)聽Container到生命周期媳谁,動態(tài)調(diào)整Mapper中的Container涂滴。
通過Mapper找到目標Container后,就可以轉(zhuǎn)發(fā)給Container來處理了:
connector.getService().getContainer().getPipeline().getFirst().invoke(
request, response);
Container的處理流程
Adapter傳給Container的操作是將request晴音、response參數(shù)交給engine的pipeline處理柔纵。每一個級別的Container都維護了一個pipeline,用來處理請求锤躁,這是典型的流水線模式搁料,pipeline中維護了一個Valve鏈表,請求在pipeline中處理的過程就是從第一個Valve處理到最后一個系羞,Valve可以方便的進行配置來實現(xiàn)各層容器的擴展功能郭计,每個pipeline的最后一個Valve是"basic",完成基本的邏輯處理椒振,如Engine的basic將調(diào)用傳給下一級的Host的pipeline昭伸,Host的basic將調(diào)用傳給下一級的Context的pipeline,Context的basic將調(diào)用傳給下一級的Wrapper的pipeline澎迎,如Engine的basic StandardEngineValve:
public final void invoke(Request request, Response response)
throws IOException, ServletException {
// Select the Host to be used for this Request
Host host = request.getHost();
if (host == null) {
// HTTP 0.9 or HTTP 1.0 request without a host when no default host
// is defined. This is handled by the CoyoteAdapter.
return;
}
if (request.isAsyncSupported()) {
request.setAsyncSupported(host.getPipeline().isAsyncSupported());
}
// Ask this Host to process this request
host.getPipeline().getFirst().invoke(request, response);
}
而Wrapper作為最底層的Container庐杨,basic完成最終Servlet的加載、初始化嗡善,并組裝filterChain進行調(diào)用:
standardWrapperValve.invoke部分代碼
...
if (!unavailable) {
servlet = wrapper.allocate();
}
...
// Create the filter chain for this request
ApplicationFilterChain filterChain =
ApplicationFilterFactory.createFilterChain(request, wrapper, servlet);
...
filterChain.doFilter(request.getRequest(), response.getResponse());
...
那么什么時候調(diào)用了Servlet的service來處理請求呢辑莫?在filter鏈的調(diào)用過程中,鏈中所有的filter處理完成后罩引,后執(zhí)行Servlet.service來處理請求:
private void internalDoFilter(ServletRequest request,
ServletResponse response)
throws IOException, ServletException {
// Call the next filter if there is one
if (pos < n) {
...
return;
}
// We fell off the end of the chain -- call the servlet instance
//chain處理完成后各吨,執(zhí)行servlet.service
try {
...
// Use potentially wrapped request from this point
if ((request instanceof HttpServletRequest) &&
(response instanceof HttpServletResponse) &&
Globals.IS_SECURITY_ENABLED ) {
...
} else {
servlet.service(request, response);
}
至此,tomcat已經(jīng)完成了從接受連接請求到找到目標servlet來處理請求的流程袁铐,實現(xiàn)了作為Servlet容器的功能揭蜒。