Tomcat 9 源碼解析 -- Connector組件
上文中已經分析到了processKey()方法。
Poller #run() 在run方法最後調用了 processKey(sk, attachment); // 處理SelectKey
/**
processKey()這個方法主要通過調用processSocket()方法創建一個SocketProcessor,然後丟到Tomcat線程池中去執行。每個Endpoint都有自己的SocketProcessor實現,
從Endpoint的屬性中可以看到,這個Processor也有緩存機制。
總結一下Poller所做的事:遍歷PollerEvents隊列,將每個事件中的通道感興趣的事件註冊到Selector,當事件就緒時,創建一個SocketProcessor或者從緩存中取出一個SocketProcessor,
然後放到線程池執行或者直接執行它的run方法執行。
*/
protected void processKey(SelectionKey sk, NioSocketWrapper attachment) {
try {
if ( close ) {
cancelledKey(sk);
} else if ( sk.isValid() && attachment != null ) {
if (sk.isReadable() || sk.isWritable() ) {
if ( attachment.getSendfileData() != null ) {
processSendfile(sk,attachment, false);
} else {
unreg(sk, attachment, sk.readyOps());
boolean closeSocket = false;
// Read goes before write
if (sk.isReadable()) {
if (!processSocket(attachment, SocketEvent.OPEN_READ, true)) {
closeSocket = true;
}
}
if (!closeSocket && sk.isWritable()) {
if (!processSocket(attachment, SocketEvent.OPEN_WRITE, true)) {
closeSocket = true;
}
}
if (closeSocket) {
cancelledKey(sk);
}
}
}
} else {
//invalid key
cancelledKey(sk);
}
} catch ( CancelledKeyException ckx ) {
cancelledKey(sk);
} catch (Throwable t) {
ExceptionUtils.handleThrowable(t);
log.error("",t);
}
}
processKey()這個方法主要通過調用processSocket()方法創建一個SocketProcessor,然後丟到Tomcat線程池中去執行。每個Endpoint都有自己的SocketProcessor實現,從Endpoint的屬性中可以看到,這個Processor也有緩存機制。
總結一下Poller所做的事:遍歷PollerEvents隊列,將每個事件中的通道感興趣的事件註冊到Selector,當事件就緒時,創建一個SocketProcessor或者從緩存中取出一個SocketProcessor,然後放到線程池執行或者直接執行它的run方法執行。
processSocket(SocketWrapperBase<S> socketWrapper, SocketEvent event, boolean dispatch)
public boolean processSocket(SocketWrapperBase<S> socketWrapper, SocketEvent event, boolean dispatch) {
LogPropertiesTest
.debug(" -------------- 17、NioEndpoint : 執行processSocket(SocketWrapperBase<S> socketWrapper,\r\n"
+ " SocketEvent event, boolean dispatch) 方法, 執行類 :" + this.getClass());
try {
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 {
LogPropertiesTest
.debug(" -------------- 17、NioEndpoint : 執行 sc.run(); 方法, 執行類 :" + this.getClass());
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;
}
SocketProcessor
SocketProcessor實現Runnable接口,對外暴露run()方法,內部封裝doRun()。
protected class SocketProcessor extends SocketProcessorBase<NioChannel> {
public SocketProcessor(SocketWrapperBase<NioChannel> socketWrapper, SocketEvent event) {
super(socketWrapper, event);
}
@Override
protected void doRun() {
NioChannel socket = socketWrapper.getSocket();
SelectionKey key = socket.getIOChannel().keyFor(socket.getPoller().getSelector());
try {
// 這裏的 handshake 是用來標記https的握手完成情況,
// 如果是http不需要該握手階段,在從c1處直接置爲0
int handshake = -1;
try {
if (key != null) {
if (socket.isHandshakeComplete()) { // c1
handshake = 0;
} else if (event == SocketEvent.STOP || event == SocketEvent.DISCONNECT ||
event == SocketEvent.ERROR) {
// 如果不能完成TLS握手過程,標記握手失敗
handshake = -1;
} else {
// 處理https的SecureNioChannel覆寫了該hanshake()方法
// 返回註冊的SelectionKey
handshake = socket.handshake(key.isReadable(), key.isWritable());
event = SocketEvent.OPEN_READ;
}
}
} catch (IOException x) {
...
}
if (handshake == 0) { // 握手完成
SocketState state = SocketState.OPEN; // 標記Socket狀態
// 處理該Sockt裏的請求
if (event == null) {
// 2222222222
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) { // TLS會走到這裏
socketWrapper.registerReadInterest(); // 註冊讀就緒
} else if (handshake == SelectionKey.OP_WRITE) {
socketWrapper.registerWriteInterest(); // 註冊寫就緒
}
} catch (CancelledKeyException cx) {
... // 處理異常
} finally {
socketWrapper = null;
event = null;
if (running && !paused) {
processorCache.push(this); // 將SocketProcessor放回緩存中
}
}
}
}
在 22222222 處,該方法將包裝好的socketWrapper繼續傳下去,來看下調用棧, 最終在Http11Processor的service方法中處理 ,而這個Http11Processor正是Processor的一個實現類,用來真正解析流。
Http11Processor
先看一下Http11Processor的構造方法。
1 、首先調用抽象父類的構造方法,new了一個Request和Response,用於接收解析結果和Servlet處理完的內容,看這裏的Request和Response是org.apache.coyote包下的,與org.apache.catalina.connector包下的Request和Response不同。
對Request來說,前者是服務器請求的一種底層,但高效的表示,同時它也是GC-free,並且將消耗計算資源的操作作了延遲處理,可以說是按需再取。說它底層且高效是因爲它是直接操作數據流,轉換成需要的信息,所以它不適合用戶代碼。而後者connector 包下的 Request是 Coyote Request的包裝,爲用戶(也就是servlet)提供了一個高級視圖(外觀模式)。
public abstract class AbstractProcessor extends AbstractProcessorLight implements ActionHook {
private static final StringManager sm = StringManager.getManager(AbstractProcessor.class);
// Used to avoid useless B2C conversion on the host name.
private char[] hostNameC = new char[0];
protected final Adapter adapter;
protected final AsyncStateMachine asyncStateMachine;
private volatile long asyncTimeout = -1;
protected final Request request;
protected final Response response;
protected volatile SocketWrapperBase<?> socketWrapper = null;
protected volatile SSLSupport sslSupport;
/**
* Error state for the request/response currently being processed.
*/
private ErrorState errorState = ErrorState.NONE;
public AbstractProcessor(Adapter adapter) {
this(adapter, new Request(), new Response());
}
protected AbstractProcessor(Adapter adapter, Request coyoteRequest, Response
coyoteResponse) {
this.adapter = adapter;
asyncStateMachine = new AsyncStateMachine(this);
request = coyoteRequest;
response = coyoteResponse;
response.setHook(this);
request.setResponse(response);
request.setHook(this);
}
..............
}
並且在 33333333333 處可以看到傳入了一個Adapter,這個 Adapter 則是基於 coyote 的 servlet 容器中的入口點。也就是說其作用是Connector與Container之間的橋樑。
上文中 Tomcat 9 源碼解析 -- Connector組件 也提到過 :
Connector數據結構
關於Connector,有兩個非常重要的接口, ProtocolHandler 和 Adapter,前者用於處理請求,而後者則是Connector與Container容器之間的一個連接器。
public Http11Processor(AbstractHttp11Protocol<?> protocol, Adapter adapter) {
super(adapter);
this.protocol = protocol; // protocol
httpParser = new HttpParser(protocol.getRelaxedPathChars(),
protocol.getRelaxedQueryChars());
inputBuffer = new Http11InputBuffer(request, protocol.getMaxHttpHeaderSize(),
protocol.getRejectIllegalHeaderName(), httpParser);
request.setInputBuffer(inputBuffer); // 輸入緩衝,用於解析請求頭及傳輸編碼
outputBuffer = new Http11OutputBuffer(response, protocol.getMaxHttpHeaderSize());
response.setOutputBuffer(outputBuffer); // 輸出緩衝,寫headers和response主題
inputBuffer.addFilter(new IdentityInputFilter(protocol.getMaxSwallowSize()));
outputBuffer.addFilter(new IdentityOutputFilter()); // 添加身份認證過濾器
inputBuffer.addFilter(new ChunkedInputFilter(protocol.getMaxTrailerSize(),
protocol.getAllowedTrailerHeadersInternal(), protocol.getMaxExtensionSize(),
protocol.getMaxSwallowSize()));
outputBuffer.addFilter(new ChunkedOutputFilter()); // 添加分塊過濾器
// Void輸入輸出過濾器,在嘗試讀取時返回-1。 與GET,HEAD或類似請求一起使用。
inputBuffer.addFilter(new VoidInputFilter());
outputBuffer.addFilter(new VoidOutputFilter());
// 輸入過濾器負責讀取和緩衝請求體,以便它不會干擾客戶端SSL握手消息。
inputBuffer.addFilter(new BufferedInputFilter());
//inputBuffer.addFilter(new GzipInputFilter());
outputBuffer.addFilter(new GzipOutputFilter()); // Gzip
pluggableFilterIndex = inputBuffer.getFilters().length; // 標記過濾器數量
}
看完基本的構造方法,大致能瞭解這個Http11Processor的功能便是解析流,然後封裝成Request,最後給Servlet做處理。
下面來看下調用棧中提到的service方法。
可以看到處理socket分爲幾個階段:
解析——>準備——>服務——>結束輸入、輸出——>KEEPALIVE——>結束。
當然如果對於keepalive的請求來說,會在前5個階段循環。前四個階段表示了一個完成的請求處理及響應。在c4處可以看到獲取了Adapter,而這個Adapter的實現類爲CoyoteAdapter,這個Adapter將Request和Reponse的處理委託給servlet。
最終在Http11Processor的service方法中處理
@Override
public SocketState service(SocketWrapperBase<?> socketWrapper)
throws IOException {
// 包含有關請求處理的統計、管理信息。
RequestInfo rp = request.getRequestProcessor();
rp.setStage(org.apache.coyote.Constants.STAGE_PARSE); // 解析階段
// Setting up the I/O
setSocketWrapper(socketWrapper);// 初始化I/O設置,
inputBuffer.init(socketWrapper);
outputBuffer.init(socketWrapper);
// Flags
keepAlive = true;// 標誌位
openSocket = false;
readComplete = true;
boolean keptAlive = false;
SendfileState sendfileState = SendfileState.DONE;
while (!getErrorState().isError() && keepAlive && !isAsync() && upgradeToken == null &&
sendfileState == SendfileState.DONE && !protocol.isPaused()) {
// Parsing the request header
//解析請求頭信息 從buffer中讀取並解析請求基本信息,比如方法(GET/POST/PUT等等)、URI、協議等等
try {
if (!inputBuffer.parseRequestLine(keptAlive, protocol.getConnectionTimeout(),
protocol.getKeepAliveTimeout())) {
if (inputBuffer.getParsingRequestLinePhase() == -1) {
return SocketState.UPGRADING;
} else if (handleIncompleteRequestLineRead()) {
break;
}
}
if (protocol.isPaused()) {
// 503 - Service unavailable
response.setStatus(503); // 如果協議解析服務被暫停,則返回503
setErrorState(ErrorState.CLOSE_CLEAN, null);
} else {
keptAlive = true;
// Set this every time in case limit has been changed via JMX
// 每次更新header屬性的數量限制(可以通過JMX修改)
request.getMimeHeaders().setLimit(protocol.getMaxHeaderCount());
if (!inputBuffer.parseHeaders()) {
// We've read part of the request, don't recycle it
// instead associate it with the socket
openSocket = true;
readComplete = false;
break;
}
if (!protocol.getDisableUploadTimeout()) {
socketWrapper.setReadTimeout(protocol.getConnectionUploadTimeout());
}
}
} catch (IOException e) {
if (log.isDebugEnabled()) {
log.debug(sm.getString("http11processor.header.parse"), e);
}
setErrorState(ErrorState.CLOSE_CONNECTION_NOW, e);
break;
} catch (Throwable t) {
ExceptionUtils.handleThrowable(t);
UserDataHelper.Mode logMode = userDataHelper.getNextMode();
if (logMode != null) {
String message = sm.getString("http11processor.header.parse");
switch (logMode) {
case INFO_THEN_DEBUG:
message += sm.getString("http11processor.fallToDebug");
//$FALL-THROUGH$
case INFO:
log.info(message, t);
break;
case DEBUG:
log.debug(message, t);
}
}
// 400 - Bad Request
response.setStatus(400); // 返回400 異常
setErrorState(ErrorState.CLOSE_CLEAN, t);
}
// Has an upgrade been requested?
Enumeration<String> connectionValues = request.getMimeHeaders().values("Connection");
boolean foundUpgrade = false;
while (connectionValues.hasMoreElements() && !foundUpgrade) {
foundUpgrade = connectionValues.nextElement().toLowerCase(
Locale.ENGLISH).contains("upgrade");
}
if (foundUpgrade) {
// Check the protocol 檢查協議
// 如果包含upgrade,表示協議需要升級
String requestedProtocol = request.getHeader("Upgrade"); // 獲取升級協議
UpgradeProtocol upgradeProtocol = protocol.getUpgradeProtocol(requestedProtocol);
if (upgradeProtocol != null) {
if (upgradeProtocol.accept(request)) {
response.setStatus(HttpServletResponse.SC_SWITCHING_PROTOCOLS);
response.setHeader("Connection", "Upgrade"); // 設置響應體
response.setHeader("Upgrade", requestedProtocol);
action(ActionCode.CLOSE, null);
getAdapter().log(request, response, 0);
InternalHttpUpgradeHandler upgradeHandler =
upgradeProtocol.getInternalUpgradeHandler(
socketWrapper, getAdapter(), cloneRequest(request));
UpgradeToken upgradeToken = new UpgradeToken(upgradeHandler, null, null);
action(ActionCode.UPGRADE, upgradeToken);
return SocketState.UPGRADING;
}
}
}
if (getErrorState().isIoAllowed()) {
// Setting up filters, and parse some request headers
rp.setStage(org.apache.coyote.Constants.STAGE_PREPARE);
try {
// 主要設置過濾器,並且解析部分headers
// 比如檢查是否是keepAlive、如果是http/1.1,判斷是否包含Expect:100-continue
// (用於客戶端在發送POST數據給服務器前,徵詢服務器情況,
// 看服務器是否處理POST的數據,常用於大文件post,例如文件上傳)、
// 用戶代理user-agent狀況、host等等
prepareRequest();
} catch (Throwable t) {
ExceptionUtils.handleThrowable(t);
if (log.isDebugEnabled()) {
log.debug(sm.getString("http11processor.request.prepare"), t);
}
// 500 - Internal Server Error
response.setStatus(500);
setErrorState(ErrorState.CLOSE_CLEAN, t);
}
}
// 如果是長連接,則需要判斷長連接是否達到服務器上限
int maxKeepAliveRequests = protocol.getMaxKeepAliveRequests();
if (maxKeepAliveRequests == 1) {
keepAlive = false;
} else if (maxKeepAliveRequests > 0 &&
socketWrapper.decrementKeepAlive() <= 0) {
keepAlive = false;
}
// Process the request in the adapter
// 通過Adapter交給Container處理請求,並構建Response
if (getErrorState().isIoAllowed()) {
try {
rp.setStage(org.apache.coyote.Constants.STAGE_SERVICE);
getAdapter().service(request, response);
// Handle when the response was committed before a serious
// error occurred. Throwing a ServletException should both
// set the status to 500 and set the errorException.
// If we fail here, then the response is likely already
// committed, so we can't try and set headers.
if(keepAlive && !getErrorState().isError() && !isAsync() &&
statusDropsConnection(response.getStatus())) {
setErrorState(ErrorState.CLOSE_CLEAN, null);
}
} catch (InterruptedIOException e) {
setErrorState(ErrorState.CLOSE_CONNECTION_NOW, e);
} catch (HeadersTooLargeException e) {
log.error(sm.getString("http11processor.request.process"), e);
// The response should not have been committed but check it
// anyway to be safe
if (response.isCommitted()) {
setErrorState(ErrorState.CLOSE_NOW, e);
} else {
response.reset();
response.setStatus(500);
setErrorState(ErrorState.CLOSE_CLEAN, e);
response.setHeader("Connection", "close"); // TODO: Remove
}
} catch (Throwable t) {
ExceptionUtils.handleThrowable(t);
log.error(sm.getString("http11processor.request.process"), t);
// 500 - Internal Server Error
response.setStatus(500);
setErrorState(ErrorState.CLOSE_CLEAN, t);
getAdapter().log(request, response, 0);
}
}
// Finish the handling of the request
// 完成 request請求處理
rp.setStage(org.apache.coyote.Constants.STAGE_ENDINPUT);
if (!isAsync()) {
// If this is an async request then the request ends when it has
// been completed. The AsyncContext is responsible for calling
// endRequest() in that case.
// 如果這是異步請求,則請求在完成後結束。
// 在這種情況下,AsyncContext負責調用endRequest()。
endRequest();
}
rp.setStage(org.apache.coyote.Constants.STAGE_ENDOUTPUT);
// If there was an error, make sure the request is counted as
// and error, and update the statistics counter
// 確保設置錯誤碼,且更新請求的統計計數
if (getErrorState().isError()) {
response.setStatus(500);
}
if (!isAsync() || getErrorState().isError()) {
request.updateCounters();
if (getErrorState().isIoAllowed()) {
inputBuffer.nextRequest();
outputBuffer.nextRequest();
}
}
if (!protocol.getDisableUploadTimeout()) {
int connectionTimeout = protocol.getConnectionTimeout();
if(connectionTimeout > 0) {
socketWrapper.setReadTimeout(connectionTimeout);
} else {
socketWrapper.setReadTimeout(0);
}
}
// 如果是長連接繼續循環
rp.setStage(org.apache.coyote.Constants.STAGE_KEEPALIVE);
sendfileState = processSendfile(socketWrapper);
}
rp.setStage(org.apache.coyote.Constants.STAGE_ENDED);
if (getErrorState().isError() || protocol.isPaused()) {
return SocketState.CLOSED;
} else if (isAsync()) {
return SocketState.LONG;
} else if (isUpgrade()) {
return SocketState.UPGRADING;
} else {
if (sendfileState == SendfileState.PENDING) {
return SocketState.SENDFILE;
} else {
if (openSocket) {
if (readComplete) {
return SocketState.OPEN;
} else {
return SocketState.LONG;
}
} else {
return SocketState.CLOSED;
}
}
}
}
Connector的對請求數據流的處理流程基本已經完成。
接下去便是交由Container組件去做具體的Servlet處理了。