restTemplate源碼解析(四)執行ClientHttpRequest請求對象


所有文章

https://www.cnblogs.com/lay2017/p/11740855.html

 

正文

上一篇文章中,我們創建了一個ClientHttpRequest的實例。本文將繼續閱讀ClientHttpRequest的執行邏輯。

再次回顧一下restTemplate核心邏輯的代碼

protected <T> T doExecute(URI url, @Nullable HttpMethod method, @Nullable RequestCallback requestCallback,
        @Nullable ResponseExtractor<T> responseExtractor) throws RestClientException {

    ClientHttpResponse response = null;
    try {
        // 生成請求
        ClientHttpRequest request = createRequest(url, method);
        if (requestCallback != null) {
            // 設置header
            requestCallback.doWithRequest(request);
        }
        // 執行請求,獲取響應
        response = request.execute(); // 處理響應
        handleResponse(url, method, response);
        // 獲取響應體對象
        return (responseExtractor != null ? responseExtractor.extractData(response) : null);
    }
    catch (IOException ex) {
        // ... 拋出異常
    }
    finally {
        if (response != null) {
            // 關閉響應流
            response.close();
        }
    }
}

 

ClientHttpRequest的默認實現類是SimpleBufferingClientHttpRequest,我們先看看它的繼承關系

可以看到,ClientHttpRequest直接被AbstractClientHttpRequest繼承,所以我們先從AbstractClientHttpRequest實現的execute方法開始

 

跟進execute方法

@Override
public final ClientHttpResponse execute() throws IOException {
    assertNotExecuted();
    ClientHttpResponse result = executeInternal(this.headers);
    this.executed = true;
    return result;
}

execute方法前置校驗executed這個flag,executeInternal執行完后打了個true的標記。所以一個ClientHttpRequest將只能被執行一次。

 

繼續跟進executeInternal方法,executeInternal方法由AbstractBufferingClientHttpRequest實現

@Override
protected ClientHttpResponse executeInternal(HttpHeaders headers) throws IOException {
    byte[] bytes = this.bufferedOutput.toByteArray();
    if (headers.getContentLength() < 0) {
        headers.setContentLength(bytes.length);
    }
    ClientHttpResponse result = executeInternal(headers, bytes); this.bufferedOutput = new ByteArrayOutputStream(0);
    return result;
}

核心邏輯在executeInternal(headers, bytes)里,繼續跟進它

 

executeInternal(headers, bytes)由SimpleBufferingClientHttpRequest實現

@Override
protected ClientHttpResponse executeInternal(HttpHeaders headers, byte[] bufferedOutput) throws IOException {
    addHeaders(this.connection, headers);
    // JDK <1.8 doesn't support getOutputStream with HTTP DELETE
    if (getMethod() == HttpMethod.DELETE && bufferedOutput.length == 0) {
        this.connection.setDoOutput(false);
    }
    if (this.connection.getDoOutput() && this.outputStreaming) {
        this.connection.setFixedLengthStreamingMode(bufferedOutput.length);
    }
    this.connection.connect();
    if (this.connection.getDoOutput()) {
        // 寫到輸出流上
        FileCopyUtils.copy(bufferedOutput, this.connection.getOutputStream());
    }
    else {
        // Immediately trigger the request in a no-output scenario as well
        this.connection.getResponseCode();
    }
    // 響應一個ClientHttpResponse對象
    return new SimpleClientHttpResponse(this.connection);
}

如果開啟了輸出流,那么FileCopyUtils.copy方法將會把緩沖數據寫入到輸出流里面。

注意:FileCopyUtils.copy方法在寫入完畢后會關閉輸出流,所以不需要外部顯式關閉。我們看copy方法

public static void copy(byte[] in, OutputStream out) throws IOException {
    Assert.notNull(in, "No input byte array specified");
    Assert.notNull(out, "No OutputStream specified");

    try {
        out.write(in);
    }
    finally {
        try {
            out.close();
        }
        catch (IOException ex) {
        }
    }
}

 

executerInternal(headers, bytes)方法最后會響應一個SimpleClientHttpResponse實例對象,單純地包裝了Connection對象。

SimpleClientHttpResponse(HttpURLConnection connection) {
    this.connection = connection;
}

顯然,后續的處理就是從ClientHttpResponse中讀取輸入流,然后格式化成一個響應體,最后回收資源。下一篇內容講述這個

 

總結

執行ClientHttpRequest邏輯其實就是與服務端創建Connection連接(如果有需要寫入數據則寫入到輸出流),整體還是比較簡單的。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM