Request在tomcat中是一個非常核心的的實例,下面以NIO爲例來解讀一下在各個時期下的狀態(其實在Tomcat的幾種模式中到了這裏之後的處理都是差不多的)
1.1 創建coyote/Request
這個request並不是我們最終在servlet中使用的Request,它是tomcat內部處理請求的一種有效方法,其創建過程是在接收到客戶請求處理套接字構建Processor具體實現類的構造器中構建,以NIO模式爲例則是在實例化請求處理類Http11NioProcessor時候構建,具體執行流程如下:
Http11NioProcessor.java
public Http11NioProcessor(int maxHttpHeaderSize, NioEndpoint endpoint, int maxTrailerSize,
Set<String> allowedTrailerHeaders, int maxExtensionSize, int maxSwallowSize) {
super(endpoint);
inputBuffer = new InternalNioInputBuffer(request, maxHttpHeaderSize);
request.setInputBuffer(inputBuffer);
outputBuffer = new InternalNioOutputBuffer(response, maxHttpHeaderSize);
response.setOutputBuffer(outputBuffer);
initializeFilters(maxTrailerSize, allowedTrailerHeaders, maxExtensionSize, maxSwallowSize);
}
AbstractHttp11Processor.java
public AbstractHttp11Processor(AbstractEndpoint<S> endpoint) {
super(endpoint);
userDataHelper = new UserDataHelper(getLog());
}
AbstractProcessor.java
public AbstractProcessor(AbstractEndpoint<S> endpoint) {
this.endpoint = endpoint;
asyncStateMachine = new AsyncStateMachine(this);
request = new Request();
response = new Response();
response.setHook(this);
request.setResponse(response);
request.setHook(this);
}
根據這個過程不難看出在實例化中逐級顯示調用父級有參構造器,將對應的endpoint賦給Processor實現類的句柄,而後繼續實例化Request,並將當前實例注入到新構建的request實例,另外response也被注入request作爲句柄。
1.2 Coyote/Request的執行與結束
Coyote/Request的執行與結束主要是在Processor. process在這個過程中會獲取RequestInfo這個句柄其是一個request初始化實例句柄,在這個方法中通過setRequestLineReadTimeout方法解析了請求行如Method URL HTTP/1.1利用parseRequestLine剩餘的首部信息最終調用request中相關的方法將解析的信息(大部分是MessageByte)注入到其成員屬性中(詳見requets解析http頭部請求),然後進行的是調用Adapter的service方法進行處理(見下一小節),之後利用endRequest將當前請求處理完成,在這個過程還包含將流給提交http中去,最後調用nextRequest將當前request實例部分屬性置空,所以當前實例依舊存在。
public SocketState process(SocketWrapper<S> socketWrapper)
throws IOException {
//獲取請求信息句柄,其在定義的時候直接初始化的一個RequestInfo實例
RequestInfo rp = request.getRequestProcessor();
//設置RequestInfo的狀態爲解析狀態 stage_parse
rp.setStage(org.apache.coyote.Constants.STAGE_PARSE);
。。。。。。
while (!getErrorState().isError() && keepAlive && !comet && !isAsync() && upgradeToken == null && !endpoint.isPaused()) {
。。。。。。
//設置請求閱讀時間,以及將socketInputStream中的數據寫入到buf
setRequestLineReadTimeout();
//if判斷裏只是解析了第一行,方法名 請求URL 協議
if (!getInputBuffer().parseRequestLine(keptAlive)) {
//如果解析失敗,處理未完成的請
if (handleIncompleteRequestLineRead()) {
break;
}
。。。。。。。。
}
if (!getErrorState().isError()) {
//設置過濾器準備解析
rp.setStage(org.apache.coyote.Constants.STAGE_PREPARE);
try {
//解析請求,根據url將對應的Host Context Wrapper匹配到該請request的屬性中
prepareRequest();
} catch (Throwable t) {
。。。。。。。。
}
}
//最大的長連接數
if (maxKeepAliveRequests == 1) {
keepAlive = false;
} else if (maxKeepAliveRequests > 0 &&
socketWrapper.decrementKeepAlive() <= 0) {
keepAlive = false;
}
// 在適配器中執行請求
if (!getErrorState().isError()) {
//設置request的狀態爲開始調用適配器的service
rp.setStage(org.apache.coyote.Constants.STAGE_SERVICE);
//調用適配器的service方法
getAdapter().service(request, response);
。。。。。。。
}
rp.setStage(org.apache.coyote.Constants.STAGE_ENDINPUT);
if (!isAsync() && !comet) {
。。。。。。
endRequest();
}
rp.setStage(org.apache.coyote.Constants.STAGE_ENDOUTPUT);
if (!isAsync() && !comet || getErrorState().isError()) {
request.updateCounters();
if (getErrorState().isIoAllowed()) {
getInputBuffer().nextRequest();
getOutputBuffer().nextRequest();
}
}
。。。。。。
rp.setStage(org.apache.coyote.Constants.STAGE_KEEPALIVE);
}
rp.setStage(org.apache.coyote.Constants.STAGE_ENDED);
}
1.3 創建Coonnector/Request和Connector/Response
這兩個實例和是從相應的Coyote對應實例的Notes 數組中獲取的,如果沒有則實例化一個並且注入,這是因爲Coyote和Coonnector中相關實例是一一對應,只不過Coyote主要是負責和http打交道而Coonnector是和程序員打交道,但是請注意我們並不是直接使用的Coonnector中Request/Response。後面講述
//從org.apache.coyote.Request的note數組屬性中獲取Request對象
Request request = (Request) req.getNote(ADAPTER_NOTES);
//從org.apache.coyote.Response的note數組屬性中獲取Response對象
Response response = (Response) res.getNote(ADAPTER_NOTES);
//解析:ADAPTER_NOTES=1 這是因爲notes這個數組不知存放了相應request/Response實例 還有cookie等 1代表的是Request/Response
if (request == null) {
//創建一個connector的request對象
request = connector.createRequest();
//將Coyote中request注入連接器中
request.setCoyoteRequest(req);
response = connector.createResponse();
response.setCoyoteResponse(res);
//request response相互關聯
request.setResponse(response);
response.setRequest(request);
//設置爲notes
req.setNote(ADAPTER_NOTES, request);
res.setNote(ADAPTER_NOTES, response);
req.getParameters().setQueryStringEncoding
(connector.getURIEncoding());
}
if (connector.getXpoweredBy()) {
response.addHeader("X-Powered-By", POWERED_BY);
}
1.4 Coonnector/Request和Connector/Response的執行過程
其創建之後就直接通過獲取service不斷調用管道一下向下執行找到對應的servlet進行執行,其過程如下:
connector.getService().getContainer().getPipeline().getFirst().invoke(request, response);
在這個過程中,針對Request/Response的生命歷程,我們應該提的是StandardWrapperValve這個閥門執行的代碼是如下:
filterChain.doFilter(request.getRequest(),response.getResponse())
public HttpServletRequest getRequest() {
if (facade == null) {
facade = new RequestFacade(this);
}
return facade;
}
可以看出在這裏採用了外觀模式創建了RequestFacade實例,並作爲參數不斷向下傳遞,這就是我們在servlet中使用的RequestFacade這個實例在servlet執行完畢,接着管道繼續向下執到finishRequest, finishResponse完成當前請求,其中finishResponse是將最終的相應數據給發送到客戶端
1.5 Coonnector/Request和Connector/Response的結束處理
Request/Response也不是直接從內存釋放,僅僅只是其中部分屬性給置空,下一個socket請求的時候調用的是對應的Processor具體實現類則可以直接進行獲取。置空代碼如下:
if (!comet && !async) {
request.recycle();
response.recycle();
} else {
request.clearEncoders();
response.clearEncoders();
}
由於Request請求跟瀏覽器無關,可能多次請求是一個Request實例,也可能是不同實例,但是在請求中Request實例中對應的成員屬性都被清空,所以可以說Request的作用域是單個請求,Response也是同樣的道理