tomcat源碼解讀五 Tomcat中Request的生命歷程

     Request在tomcat中是一個非常核心的的實例,下面以NIO爲例來解讀一下在各個時期下的狀態(其實在Tomcat的幾種模式中到了這裏之後的處理都是差不多的)

1.1 創建coyote/Request

     這個request並不是我們最終在servlet中使用的Request,它是tomcat內部處理請求的一種有效方法,其創建過程是在接收到客戶請求處理套接字構建Processor具體實現類的構造器中構建,以NIO模式爲例則是在實例化請求處理類Http11NioProcessor時候構建,具體執行流程如下:
  (實例化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也是同樣的道理

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章