提交 20c41774 编写于 作者: A Arjen Poutsma

Merge pull request #350 from ok2c/httpclient_4_3

* httpclient_4_3:
  Post SPR-8804 optimizations: better use of HC 4.3 APIs
...@@ -27,8 +27,8 @@ import org.apache.http.HttpEntity; ...@@ -27,8 +27,8 @@ import org.apache.http.HttpEntity;
import org.apache.http.HttpEntityEnclosingRequest; import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpResponse; import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpUriRequest; import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.nio.client.HttpAsyncClient; import org.apache.http.nio.client.HttpAsyncClient;
import org.apache.http.nio.entity.NByteArrayEntity;
import org.apache.http.protocol.HttpContext; import org.apache.http.protocol.HttpContext;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
...@@ -79,7 +79,7 @@ final class HttpComponentsAsyncClientHttpRequest extends AbstractBufferingAsyncC ...@@ -79,7 +79,7 @@ final class HttpComponentsAsyncClientHttpRequest extends AbstractBufferingAsyncC
if (this.httpRequest instanceof HttpEntityEnclosingRequest) { if (this.httpRequest instanceof HttpEntityEnclosingRequest) {
HttpEntityEnclosingRequest entityEnclosingRequest = HttpEntityEnclosingRequest entityEnclosingRequest =
(HttpEntityEnclosingRequest) this.httpRequest; (HttpEntityEnclosingRequest) this.httpRequest;
HttpEntity requestEntity = new ByteArrayEntity(bufferedOutput); HttpEntity requestEntity = new NByteArrayEntity(bufferedOutput);
entityEnclosingRequest.setEntity(requestEntity); entityEnclosingRequest.setEntity(requestEntity);
} }
...@@ -117,14 +117,14 @@ final class HttpComponentsAsyncClientHttpRequest extends AbstractBufferingAsyncC ...@@ -117,14 +117,14 @@ final class HttpComponentsAsyncClientHttpRequest extends AbstractBufferingAsyncC
public ClientHttpResponse get() public ClientHttpResponse get()
throws InterruptedException, ExecutionException { throws InterruptedException, ExecutionException {
HttpResponse response = futureResponse.get(); HttpResponse response = futureResponse.get();
return new HttpComponentsClientHttpResponse(response); return new HttpComponentsAsyncClientHttpResponse(response);
} }
@Override @Override
public ClientHttpResponse get(long timeout, TimeUnit unit) public ClientHttpResponse get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException { throws InterruptedException, ExecutionException, TimeoutException {
HttpResponse response = futureResponse.get(timeout, unit); HttpResponse response = futureResponse.get(timeout, unit);
return new HttpComponentsClientHttpResponse(response); return new HttpComponentsAsyncClientHttpResponse(response);
} }
} }
......
...@@ -20,10 +20,16 @@ import java.io.IOException; ...@@ -20,10 +20,16 @@ import java.io.IOException;
import java.net.URI; import java.net.URI;
import org.apache.http.client.HttpClient; import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.Configurable;
import org.apache.http.client.methods.HttpUriRequest; import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;
import org.apache.http.impl.nio.client.HttpAsyncClients; import org.apache.http.impl.nio.client.HttpAsyncClients;
import org.apache.http.nio.client.HttpAsyncClient; import org.apache.http.nio.client.HttpAsyncClient;
import org.apache.http.nio.reactor.IOReactorStatus; import org.apache.http.nio.reactor.IOReactorStatus;
import org.apache.http.protocol.HttpContext;
import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.InitializingBean;
import org.springframework.http.HttpMethod; import org.springframework.http.HttpMethod;
import org.springframework.util.Assert; import org.springframework.util.Assert;
...@@ -41,7 +47,7 @@ public class HttpComponentsAsyncClientHttpRequestFactory ...@@ -41,7 +47,7 @@ public class HttpComponentsAsyncClientHttpRequestFactory
extends HttpComponentsClientHttpRequestFactory extends HttpComponentsClientHttpRequestFactory
implements AsyncClientHttpRequestFactory, InitializingBean { implements AsyncClientHttpRequestFactory, InitializingBean {
private HttpAsyncClient httpAsyncClient; private CloseableHttpAsyncClient httpAsyncClient;
/** /**
...@@ -49,7 +55,7 @@ public class HttpComponentsAsyncClientHttpRequestFactory ...@@ -49,7 +55,7 @@ public class HttpComponentsAsyncClientHttpRequestFactory
* with a default {@link HttpAsyncClient} and {@link HttpClient}. * with a default {@link HttpAsyncClient} and {@link HttpClient}.
*/ */
public HttpComponentsAsyncClientHttpRequestFactory() { public HttpComponentsAsyncClientHttpRequestFactory() {
this(HttpAsyncClients.createDefault()); this(HttpAsyncClients.createSystem());
} }
/** /**
...@@ -57,7 +63,7 @@ public class HttpComponentsAsyncClientHttpRequestFactory ...@@ -57,7 +63,7 @@ public class HttpComponentsAsyncClientHttpRequestFactory
* with the given {@link HttpAsyncClient} instance and a default {@link HttpClient}. * with the given {@link HttpAsyncClient} instance and a default {@link HttpClient}.
* @param httpAsyncClient the HttpAsyncClient instance to use for this request factory * @param httpAsyncClient the HttpAsyncClient instance to use for this request factory
*/ */
public HttpComponentsAsyncClientHttpRequestFactory(HttpAsyncClient httpAsyncClient) { public HttpComponentsAsyncClientHttpRequestFactory(CloseableHttpAsyncClient httpAsyncClient) {
super(); super();
Assert.notNull(httpAsyncClient, "'httpAsyncClient' must not be null"); Assert.notNull(httpAsyncClient, "'httpAsyncClient' must not be null");
this.httpAsyncClient = httpAsyncClient; this.httpAsyncClient = httpAsyncClient;
...@@ -69,8 +75,8 @@ public class HttpComponentsAsyncClientHttpRequestFactory ...@@ -69,8 +75,8 @@ public class HttpComponentsAsyncClientHttpRequestFactory
* @param httpClient the HttpClient instance to use for this request factory * @param httpClient the HttpClient instance to use for this request factory
* @param httpAsyncClient the HttpAsyncClient instance to use for this request factory * @param httpAsyncClient the HttpAsyncClient instance to use for this request factory
*/ */
public HttpComponentsAsyncClientHttpRequestFactory(HttpClient httpClient, public HttpComponentsAsyncClientHttpRequestFactory(CloseableHttpClient httpClient,
HttpAsyncClient httpAsyncClient) { CloseableHttpAsyncClient httpAsyncClient) {
super(httpClient); super(httpClient);
Assert.notNull(httpAsyncClient, "'httpAsyncClient' must not be null"); Assert.notNull(httpAsyncClient, "'httpAsyncClient' must not be null");
this.httpAsyncClient = httpAsyncClient; this.httpAsyncClient = httpAsyncClient;
...@@ -80,7 +86,7 @@ public class HttpComponentsAsyncClientHttpRequestFactory ...@@ -80,7 +86,7 @@ public class HttpComponentsAsyncClientHttpRequestFactory
* Set the {@code HttpClient} used for * Set the {@code HttpClient} used for
* {@linkplain #createAsyncRequest(java.net.URI, org.springframework.http.HttpMethod) asynchronous execution}. * {@linkplain #createAsyncRequest(java.net.URI, org.springframework.http.HttpMethod) asynchronous execution}.
*/ */
public void setHttpAsyncClient(HttpAsyncClient httpAsyncClient) { public void setHttpAsyncClient(CloseableHttpAsyncClient httpAsyncClient) {
this.httpAsyncClient = httpAsyncClient; this.httpAsyncClient = httpAsyncClient;
} }
...@@ -88,7 +94,7 @@ public class HttpComponentsAsyncClientHttpRequestFactory ...@@ -88,7 +94,7 @@ public class HttpComponentsAsyncClientHttpRequestFactory
* Return the {@code HttpClient} used for * Return the {@code HttpClient} used for
* {@linkplain #createAsyncRequest(URI, HttpMethod) asynchronous execution}. * {@linkplain #createAsyncRequest(URI, HttpMethod) asynchronous execution}.
*/ */
public HttpAsyncClient getHttpAsyncClient() { public CloseableHttpAsyncClient getHttpAsyncClient() {
return httpAsyncClient; return httpAsyncClient;
} }
...@@ -98,7 +104,7 @@ public class HttpComponentsAsyncClientHttpRequestFactory ...@@ -98,7 +104,7 @@ public class HttpComponentsAsyncClientHttpRequestFactory
} }
private void startAsyncClient() { private void startAsyncClient() {
HttpAsyncClient asyncClient = getHttpAsyncClient(); CloseableHttpAsyncClient asyncClient = getHttpAsyncClient();
if (asyncClient.getStatus() != IOReactorStatus.ACTIVE) { if (asyncClient.getStatus() != IOReactorStatus.ACTIVE) {
asyncClient.start(); asyncClient.start();
} }
...@@ -111,8 +117,23 @@ public class HttpComponentsAsyncClientHttpRequestFactory ...@@ -111,8 +117,23 @@ public class HttpComponentsAsyncClientHttpRequestFactory
startAsyncClient(); startAsyncClient();
HttpUriRequest httpRequest = createHttpUriRequest(httpMethod, uri); HttpUriRequest httpRequest = createHttpUriRequest(httpMethod, uri);
postProcessHttpRequest(httpRequest); postProcessHttpRequest(httpRequest);
return new HttpComponentsAsyncClientHttpRequest(asyncClient, httpRequest, HttpContext context = createHttpContext(httpMethod, uri);
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 = RequestConfig.DEFAULT;
}
context.setAttribute(HttpClientContext.REQUEST_CONFIG, config);
}
return new HttpComponentsAsyncClientHttpRequest(asyncClient, httpRequest, context);
} }
@Override @Override
...@@ -121,7 +142,7 @@ public class HttpComponentsAsyncClientHttpRequestFactory ...@@ -121,7 +142,7 @@ public class HttpComponentsAsyncClientHttpRequestFactory
super.destroy(); super.destroy();
} }
finally { finally {
getHttpAsyncClient().shutdown(); getHttpAsyncClient().close();
} }
} }
} }
/*
* Copyright 2002-2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.http.client;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.util.EntityUtils;
import org.springframework.http.HttpHeaders;
import java.io.IOException;
import java.io.InputStream;
/**
* {@link ClientHttpResponse} implementation that uses
* Apache HttpComponents HttpClient to execute requests.
*
* <p>Created via the {@link HttpComponentsAsyncClientHttpRequest}.
*
* @author Oleg Kalnichevski
* @author Arjen Poutsma
* @since 3.1
* @see HttpComponentsAsyncClientHttpRequest#executeAsync()
*/
final class HttpComponentsAsyncClientHttpResponse extends AbstractClientHttpResponse {
private final HttpResponse httpResponse;
private HttpHeaders headers;
HttpComponentsAsyncClientHttpResponse(HttpResponse httpResponse) {
this.httpResponse = httpResponse;
}
@Override
public int getRawStatusCode() throws IOException {
return this.httpResponse.getStatusLine().getStatusCode();
}
@Override
public String getStatusText() throws IOException {
return this.httpResponse.getStatusLine().getReasonPhrase();
}
@Override
public HttpHeaders getHeaders() {
if (this.headers == null) {
this.headers = new HttpHeaders();
for (Header header : this.httpResponse.getAllHeaders()) {
this.headers.add(header.getName(), header.getValue());
}
}
return this.headers;
}
@Override
public InputStream getBody() throws IOException {
HttpEntity entity = this.httpResponse.getEntity();
return entity != null ? entity.getContent() : null;
}
@Override
public void close() {
// HTTP responses returned by async HTTP client
// are not bound to an active connection and
// do not have to deallocate any resources
}
}
...@@ -21,6 +21,8 @@ import java.net.URI; ...@@ -21,6 +21,8 @@ import java.net.URI;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.impl.client.CloseableHttpClient;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod; import org.springframework.http.HttpMethod;
...@@ -46,14 +48,14 @@ import org.apache.http.protocol.HttpContext; ...@@ -46,14 +48,14 @@ import org.apache.http.protocol.HttpContext;
*/ */
final class HttpComponentsClientHttpRequest extends AbstractBufferingClientHttpRequest { final class HttpComponentsClientHttpRequest extends AbstractBufferingClientHttpRequest {
private final HttpClient httpClient; private final CloseableHttpClient httpClient;
private final HttpUriRequest httpRequest; private final HttpUriRequest httpRequest;
private final HttpContext httpContext; private final HttpContext httpContext;
public HttpComponentsClientHttpRequest(HttpClient httpClient, HttpUriRequest httpRequest, HttpContext httpContext) { public HttpComponentsClientHttpRequest(CloseableHttpClient httpClient, HttpUriRequest httpRequest, HttpContext httpContext) {
this.httpClient = httpClient; this.httpClient = httpClient;
this.httpRequest = httpRequest; this.httpRequest = httpRequest;
this.httpContext = httpContext; this.httpContext = httpContext;
...@@ -81,7 +83,7 @@ final class HttpComponentsClientHttpRequest extends AbstractBufferingClientHttpR ...@@ -81,7 +83,7 @@ final class HttpComponentsClientHttpRequest extends AbstractBufferingClientHttpR
HttpEntity requestEntity = new ByteArrayEntity(bufferedOutput); HttpEntity requestEntity = new ByteArrayEntity(bufferedOutput);
entityEnclosingRequest.setEntity(requestEntity); entityEnclosingRequest.setEntity(requestEntity);
} }
HttpResponse httpResponse = CloseableHttpResponse httpResponse =
this.httpClient.execute(this.httpRequest, this.httpContext); this.httpClient.execute(this.httpRequest, this.httpContext);
return new HttpComponentsClientHttpResponse(httpResponse); return new HttpComponentsClientHttpResponse(httpResponse);
} }
......
...@@ -20,6 +20,8 @@ import java.io.IOException; ...@@ -20,6 +20,8 @@ import java.io.IOException;
import java.net.URI; import java.net.URI;
import org.apache.http.client.HttpClient; import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.Configurable;
import org.apache.http.client.methods.HttpDelete; import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpHead; import org.apache.http.client.methods.HttpHead;
...@@ -29,8 +31,9 @@ import org.apache.http.client.methods.HttpPost; ...@@ -29,8 +31,9 @@ import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut; import org.apache.http.client.methods.HttpPut;
import org.apache.http.client.methods.HttpTrace; import org.apache.http.client.methods.HttpTrace;
import org.apache.http.client.methods.HttpUriRequest; import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients; import org.apache.http.impl.client.HttpClients;
import org.apache.http.params.CoreConnectionPNames;
import org.apache.http.protocol.HttpContext; import org.apache.http.protocol.HttpContext;
import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.DisposableBean;
...@@ -52,7 +55,9 @@ import org.springframework.util.Assert; ...@@ -52,7 +55,9 @@ import org.springframework.util.Assert;
public class HttpComponentsClientHttpRequestFactory public class HttpComponentsClientHttpRequestFactory
implements ClientHttpRequestFactory, DisposableBean { implements ClientHttpRequestFactory, DisposableBean {
private HttpClient httpClient; private int connectTimeout;
private int socketTimeout;
private CloseableHttpClient httpClient;
private boolean bufferRequestBody = true; private boolean bufferRequestBody = true;
...@@ -62,7 +67,7 @@ public class HttpComponentsClientHttpRequestFactory ...@@ -62,7 +67,7 @@ public class HttpComponentsClientHttpRequestFactory
* a default {@link HttpClient}. * a default {@link HttpClient}.
*/ */
public HttpComponentsClientHttpRequestFactory() { public HttpComponentsClientHttpRequestFactory() {
this(HttpClients.createDefault()); this(HttpClients.createSystem());
} }
/** /**
...@@ -70,24 +75,24 @@ public class HttpComponentsClientHttpRequestFactory ...@@ -70,24 +75,24 @@ public class HttpComponentsClientHttpRequestFactory
* with the given {@link HttpClient} instance. * with the given {@link HttpClient} instance.
* @param httpClient the HttpClient instance to use for this request factory * @param httpClient the HttpClient instance to use for this request factory
*/ */
public HttpComponentsClientHttpRequestFactory(HttpClient httpClient) { public HttpComponentsClientHttpRequestFactory(CloseableHttpClient httpClient) {
Assert.notNull(httpClient, "'httpClient' must not be null"); Assert.notNull(httpClient, "'httpClient' must not be null");
this.httpClient = httpClient; this.httpClient = httpClient;
} }
/** /**
* Set the {@code HttpClient} used for * Set the {@code HttpClient} used for
* {@linkplain #createRequest(URI, HttpMethod) synchronous execution}. * {@linkplain #createRequest(URI, HttpMethod) synchronous execution}.
*/ */
public void setHttpClient(HttpClient httpClient) { public void setHttpClient(CloseableHttpClient httpClient) {
this.httpClient = httpClient; this.httpClient = httpClient;
} }
/** /**
* Return the {@code HttpClient} used for * Return the {@code HttpClient} used for
* {@linkplain #createRequest(URI, HttpMethod) synchronous execution}. * {@linkplain #createRequest(URI, HttpMethod) synchronous execution}.
*/ */
public HttpClient getHttpClient() { public CloseableHttpClient getHttpClient() {
return this.httpClient; return this.httpClient;
} }
...@@ -95,24 +100,20 @@ public class HttpComponentsClientHttpRequestFactory ...@@ -95,24 +100,20 @@ public class HttpComponentsClientHttpRequestFactory
* Set the connection timeout for the underlying HttpClient. * Set the connection timeout for the underlying HttpClient.
* A timeout value of 0 specifies an infinite timeout. * A timeout value of 0 specifies an infinite timeout.
* @param timeout the timeout value in milliseconds * @param timeout the timeout value in milliseconds
* @deprecated With no direct replacement
*/ */
@Deprecated
public void setConnectTimeout(int timeout) { public void setConnectTimeout(int timeout) {
Assert.isTrue(timeout >= 0, "Timeout must be a non-negative value"); Assert.isTrue(timeout >= 0, "Timeout must be a non-negative value");
getHttpClient().getParams().setIntParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, timeout); this.connectTimeout = timeout;
} }
/** /**
* Set the socket read timeout for the underlying HttpClient. * Set the socket read timeout for the underlying HttpClient.
* A timeout value of 0 specifies an infinite timeout. * A timeout value of 0 specifies an infinite timeout.
* @param timeout the timeout value in milliseconds * @param timeout the timeout value in milliseconds
* @deprecated With no direct replacement
*/ */
@Deprecated
public void setReadTimeout(int timeout) { public void setReadTimeout(int timeout) {
Assert.isTrue(timeout >= 0, "Timeout must be a non-negative value"); Assert.isTrue(timeout >= 0, "Timeout must be a non-negative value");
getHttpClient().getParams().setIntParameter(CoreConnectionPNames.SO_TIMEOUT, timeout); this.socketTimeout= timeout;
} }
/** /**
...@@ -136,18 +137,39 @@ public class HttpComponentsClientHttpRequestFactory ...@@ -136,18 +137,39 @@ public class HttpComponentsClientHttpRequestFactory
@Override @Override
public ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod) throws IOException { public ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod) throws IOException {
HttpClient client = getHttpClient(); CloseableHttpClient client = getHttpClient();
Assert.state(client != null, Assert.state(client != null,
"Synchronous execution requires an HttpClient to be set"); "Synchronous execution requires an HttpClient to be set");
HttpUriRequest httpRequest = createHttpUriRequest(httpMethod, uri); HttpUriRequest httpRequest = createHttpUriRequest(httpMethod, uri);
postProcessHttpRequest(httpRequest); 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) {
if (this.socketTimeout > 0 || this.connectTimeout > 0) {
config = RequestConfig.custom()
.setConnectTimeout(this.connectTimeout)
.setSocketTimeout(this.socketTimeout)
.build();
} else {
config = RequestConfig.DEFAULT;
}
}
context.setAttribute(HttpClientContext.REQUEST_CONFIG, config);
}
if (bufferRequestBody) { if (bufferRequestBody) {
return new HttpComponentsClientHttpRequest(client, httpRequest, return new HttpComponentsClientHttpRequest(client, httpRequest, context);
createHttpContext(httpMethod, uri));
} }
else { else {
return new HttpComponentsStreamingClientHttpRequest(client, return new HttpComponentsStreamingClientHttpRequest(client, httpRequest, context);
httpRequest, createHttpContext(httpMethod, uri));
} }
} }
...@@ -202,12 +224,12 @@ public class HttpComponentsClientHttpRequestFactory ...@@ -202,12 +224,12 @@ public class HttpComponentsClientHttpRequestFactory
/** /**
* Shutdown hook that closes the underlying * Shutdown hook that closes the underlying
* {@link org.apache.http.conn.ClientConnectionManager ClientConnectionManager}'s * {@link org.apache.http.conn.HttpClientConnectionManager ClientConnectionManager}'s
* connection pool, if any. * connection pool, if any.
*/ */
@Override @Override
public void destroy() throws Exception { public void destroy() throws Exception {
getHttpClient().getConnectionManager().shutdown(); httpClient.close();
} }
} }
...@@ -21,7 +21,7 @@ import java.io.InputStream; ...@@ -21,7 +21,7 @@ import java.io.InputStream;
import org.apache.http.Header; import org.apache.http.Header;
import org.apache.http.HttpEntity; import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse; import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.util.EntityUtils; import org.apache.http.util.EntityUtils;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
...@@ -39,12 +39,12 @@ import org.springframework.http.HttpHeaders; ...@@ -39,12 +39,12 @@ import org.springframework.http.HttpHeaders;
*/ */
final class HttpComponentsClientHttpResponse extends AbstractClientHttpResponse { final class HttpComponentsClientHttpResponse extends AbstractClientHttpResponse {
private final HttpResponse httpResponse; private final CloseableHttpResponse httpResponse;
private HttpHeaders headers; private HttpHeaders headers;
HttpComponentsClientHttpResponse(HttpResponse httpResponse) { HttpComponentsClientHttpResponse(CloseableHttpResponse httpResponse) {
this.httpResponse = httpResponse; this.httpResponse = httpResponse;
} }
...@@ -78,16 +78,18 @@ final class HttpComponentsClientHttpResponse extends AbstractClientHttpResponse ...@@ -78,16 +78,18 @@ final class HttpComponentsClientHttpResponse extends AbstractClientHttpResponse
@Override @Override
public void close() { public void close() {
HttpEntity entity = this.httpResponse.getEntity(); // Release underlying connection back to the connection manager
if (entity != null) { try {
try { try {
// Release underlying connection back to the connection manager // Attempt to keep connection alive by consuming its remaining content
EntityUtils.consume(entity); EntityUtils.consume(this.httpResponse.getEntity());
} } finally {
catch (IOException e) { // Paranoia
// ignore this.httpResponse.close();
} }
} }
catch (IOException ignore) {
}
} }
} }
...@@ -24,9 +24,9 @@ import java.net.URI; ...@@ -24,9 +24,9 @@ import java.net.URI;
import org.apache.http.Header; import org.apache.http.Header;
import org.apache.http.HttpEntity; import org.apache.http.HttpEntity;
import org.apache.http.HttpEntityEnclosingRequest; import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpResponse; import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpUriRequest; import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.message.BasicHeader; import org.apache.http.message.BasicHeader;
import org.apache.http.protocol.HttpContext; import org.apache.http.protocol.HttpContext;
...@@ -49,7 +49,7 @@ import org.springframework.http.StreamingHttpOutputMessage; ...@@ -49,7 +49,7 @@ import org.springframework.http.StreamingHttpOutputMessage;
final class HttpComponentsStreamingClientHttpRequest extends AbstractClientHttpRequest final class HttpComponentsStreamingClientHttpRequest extends AbstractClientHttpRequest
implements StreamingHttpOutputMessage { implements StreamingHttpOutputMessage {
private final HttpClient httpClient; private final CloseableHttpClient httpClient;
private final HttpUriRequest httpRequest; private final HttpUriRequest httpRequest;
...@@ -57,7 +57,7 @@ final class HttpComponentsStreamingClientHttpRequest extends AbstractClientHttpR ...@@ -57,7 +57,7 @@ final class HttpComponentsStreamingClientHttpRequest extends AbstractClientHttpR
private Body body; private Body body;
public HttpComponentsStreamingClientHttpRequest(HttpClient httpClient, public HttpComponentsStreamingClientHttpRequest(CloseableHttpClient httpClient,
HttpUriRequest httpRequest, HttpContext httpContext) { HttpUriRequest httpRequest, HttpContext httpContext) {
this.httpClient = httpClient; this.httpClient = httpClient;
this.httpRequest = httpRequest; this.httpRequest = httpRequest;
...@@ -97,7 +97,7 @@ final class HttpComponentsStreamingClientHttpRequest extends AbstractClientHttpR ...@@ -97,7 +97,7 @@ final class HttpComponentsStreamingClientHttpRequest extends AbstractClientHttpR
HttpEntity requestEntity = new StreamingHttpEntity(getHeaders(), body); HttpEntity requestEntity = new StreamingHttpEntity(getHeaders(), body);
entityEnclosingRequest.setEntity(requestEntity); entityEnclosingRequest.setEntity(requestEntity);
} }
HttpResponse httpResponse = CloseableHttpResponse httpResponse =
this.httpClient.execute(this.httpRequest, this.httpContext); this.httpClient.execute(this.httpRequest, this.httpContext);
return new HttpComponentsClientHttpResponse(httpResponse); return new HttpComponentsClientHttpResponse(httpResponse);
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册