http調用之RestTemplate

核心方法爲org.springframework.web.client.RestTemplate.doExecute(URI, HttpMethod, RequestCallback, ResponseExtractor<T>)web

方法內容以下:spring

 

 其中,重點在下面這三行apache

 

 ClientHttpRequest是http請求調用的抽象,具體實現有jdk自帶的以及apache的httpclient,實現類以下:緩存

 

simple開頭的是使用jdk自帶的net操做,Components的底層是httpclient操做。post

 AbstractBufferingClientHttpRequest爲緩存requestbody的基類,內部bufferedOutput保存了requestbody的內容,避免流的二次讀取會致使讀取不到數據。this

那麼,究竟是哪裏給這個ByteArrayOutputStream對象賦值的呢?答案就在org.springframework.web.client.RestTemplate.HttpEntityRequestCallback,註釋講得很清楚:spa

 

 在上面講到的重點強調的三行代碼中,調用了org.springframework.web.client.RestTemplate.HttpEntityRequestCallback.doWithRequest(ClientHttpRequest)方法,這個方法裏面根據requestContentType等信息,在HttpMessageConverters列表中尋找合適的HttpMessageConverter,利用這些httpMessageConverter自然的write方法將requestBody的內容通過處理轉換寫入入參HttpOutputMessage對應的getBody方法返回的OutputStream流中。然而,咱們這裏的ClientHttpRequest接口繼承自HttpOutputMessage,AbstractClientHttpRequest的getBody實現調用子類的getBodyInternal方法,重點來了,AbstractBufferingClientHttpRequest的getBodyInternal返回的就是bufferedOutput,也就是緩存的ByteArrayOutputStream。到這裏,緩存的requestbody數據有了。再囉嗦一句,使用HttpEntityRequestCallback的都是post請求的,get請求用的AcceptHeaderRequestCallback。rest

那麼,問題來了,什麼狀況下會用這個緩存數據呢?咱們看下AbstractBufferingClientHttpRequest的子類就知道了。code

這裏,又要回到剛剛的三行重點代碼,doExecute的時候調用createRequest方法返回ClientHttpRequest,實際調用父類方法org.springframework.http.client.support.HttpAccessor.createRequest(URI, HttpMethod):
對象

 

 

 org.springframework.http.client.support.InterceptingHttpAccessor.getRequestFactory()方法以下:

 

 

 若是設置了攔截器就返回InterceptingClientHttpRequestFactory,並將restTemplete原有的RequestFactory做爲參數傳入。

該factory建立的是org.springframework.http.client.InterceptingClientHttpRequest,該類重寫的executeInternal方法經過內部類InterceptingRequestExecution實現interceptors順序執行,當迭代結束後,經過以前傳進來的requestFactory建立ClientHttpRequest,並將body copy給剛剛建立的request的body,並調用execute方法,方法內容以下:

其實,InterceptingClientHttpRequest自己就帶有requestbody緩存copy功能,因此無需在建立restTemplate時包裝一個BufferingClientHttpRequestFactory,直接使用HttpComponentsClientHttpRequestFactory便可,這個factory自帶bufferRequestBody功能。

相信大部分同窗在項目中都是選擇apache的httpclient發送http請求,因此,這裏咱們重點看下org.springframework.http.client.HttpComponentsClientHttpRequestFactory,咱們看下createRequest方法:

public ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod) throws IOException {
        HttpClient client = getHttpClient();

        HttpUriRequest httpRequest = createHttpUriRequest(httpMethod, uri);
        postProcessHttpRequest(httpRequest);
        HttpContext context = createHttpContext(httpMethod, uri);
        if (context == null) {
            context = HttpClientContext.create();
        }

        // Request configuration not set in the context
        if (context.getAttribute(HttpClientContext.REQUEST_CONFIG) == null) {
            // Use request configuration given by the user, when available
            RequestConfig config = null;
            if (httpRequest instanceof Configurable) {
                config = ((Configurable) httpRequest).getConfig();
            }
            if (config == null) {
                config = createRequestConfig(client);
            }
            if (config != null) {
                context.setAttribute(HttpClientContext.REQUEST_CONFIG, config);
            }
        }
     // 默認狀況下bufferRequestBody爲true,建立使用緩存的body做爲請求體
        if (this.bufferRequestBody) {
            return new HttpComponentsClientHttpRequest(client, httpRequest, context);
        }
        else {
            return new HttpComponentsStreamingClientHttpRequest(client, httpRequest, context);
        }
    }

看下上面註釋的類的下面方法org.springframework.http.client.HttpComponentsClientHttpRequest.executeInternal(HttpHeaders, byte[]):

 

 

 這個類也是繼承自AbstractBufferingClientHttpRequest,因此剛剛InterceptingRequestExecution迭代結束後getBody返回的就是緩存的bufferedOutput,到這裏執行的時候就將bufferedOutput做爲ByteArrayEntity發送http請求。至此,結束。

相關文章
相關標籤/搜索