HttpComponentsAsyncClientHttpRequestFactory supports plain HttpAsyncClient as well

Issue: SPR-15664
This commit is contained in:
Juergen Hoeller 2017-06-14 17:10:44 +02:00
parent 137fc48cc2
commit 7b5f96c804
2 changed files with 92 additions and 37 deletions

View File

@ -16,6 +16,7 @@
package org.springframework.http.client; package org.springframework.http.client;
import java.io.Closeable;
import java.io.IOException; import java.io.IOException;
import java.net.URI; import java.net.URI;
@ -49,7 +50,7 @@ import org.springframework.util.Assert;
public class HttpComponentsAsyncClientHttpRequestFactory extends HttpComponentsClientHttpRequestFactory public class HttpComponentsAsyncClientHttpRequestFactory extends HttpComponentsClientHttpRequestFactory
implements AsyncClientHttpRequestFactory, InitializingBean { implements AsyncClientHttpRequestFactory, InitializingBean {
private CloseableHttpAsyncClient httpAsyncClient; private HttpAsyncClient asyncClient;
/** /**
@ -57,49 +58,98 @@ public class HttpComponentsAsyncClientHttpRequestFactory extends HttpComponentsC
* with a default {@link HttpAsyncClient} and {@link HttpClient}. * with a default {@link HttpAsyncClient} and {@link HttpClient}.
*/ */
public HttpComponentsAsyncClientHttpRequestFactory() { public HttpComponentsAsyncClientHttpRequestFactory() {
this(HttpAsyncClients.createSystem()); super();
this.asyncClient = HttpAsyncClients.createSystem();
} }
/** /**
* Create a new instance of the {@code HttpComponentsAsyncClientHttpRequestFactory} * Create a new instance of the {@code 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 asyncClient the HttpAsyncClient instance to use for this request factory
* @since 4.3.10
*/ */
public HttpComponentsAsyncClientHttpRequestFactory(CloseableHttpAsyncClient httpAsyncClient) { public HttpComponentsAsyncClientHttpRequestFactory(HttpAsyncClient asyncClient) {
super(); super();
Assert.notNull(httpAsyncClient, "HttpAsyncClient must not be null"); setAsyncClient(asyncClient);
this.httpAsyncClient = httpAsyncClient; }
/**
* Create a new instance of the {@code HttpComponentsAsyncClientHttpRequestFactory}
* with the given {@link CloseableHttpAsyncClient} instance and a default {@link HttpClient}.
* @param asyncClient the CloseableHttpAsyncClient instance to use for this request factory
*/
public HttpComponentsAsyncClientHttpRequestFactory(CloseableHttpAsyncClient asyncClient) {
super();
setAsyncClient(asyncClient);
} }
/** /**
* Create a new instance of the {@code HttpComponentsAsyncClientHttpRequestFactory} * Create a new instance of the {@code HttpComponentsAsyncClientHttpRequestFactory}
* with the given {@link HttpClient} and {@link HttpAsyncClient} instances. * with the given {@link HttpClient} and {@link HttpAsyncClient} instances.
* @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 asyncClient the HttpAsyncClient instance to use for this request factory
* @since 4.3.10
*/
public HttpComponentsAsyncClientHttpRequestFactory(HttpClient httpClient, HttpAsyncClient asyncClient) {
super(httpClient);
setAsyncClient(asyncClient);
}
/**
* Create a new instance of the {@code HttpComponentsAsyncClientHttpRequestFactory}
* with the given {@link CloseableHttpClient} and {@link CloseableHttpAsyncClient} instances.
* @param httpClient the CloseableHttpClient instance to use for this request factory
* @param asyncClient the CloseableHttpAsyncClient instance to use for this request factory
*/ */
public HttpComponentsAsyncClientHttpRequestFactory( public HttpComponentsAsyncClientHttpRequestFactory(
CloseableHttpClient httpClient, CloseableHttpAsyncClient httpAsyncClient) { CloseableHttpClient httpClient, CloseableHttpAsyncClient asyncClient) {
super(httpClient); super(httpClient);
Assert.notNull(httpAsyncClient, "HttpAsyncClient must not be null"); setAsyncClient(asyncClient);
this.httpAsyncClient = httpAsyncClient;
} }
/** /**
* Set the {@code HttpClient} used for * Set the {@code HttpAsyncClient} used for
* {@linkplain #createAsyncRequest(URI, HttpMethod) asynchronous execution}. * {@linkplain #createAsyncRequest(URI, HttpMethod) synchronous execution}.
* @since 4.3.10
* @see #setHttpClient(HttpClient)
*/ */
public void setHttpAsyncClient(CloseableHttpAsyncClient httpAsyncClient) { public void setAsyncClient(HttpAsyncClient asyncClient) {
this.httpAsyncClient = httpAsyncClient; Assert.notNull(asyncClient, "HttpAsyncClient must not be null");
this.asyncClient = asyncClient;
} }
/** /**
* Return the {@code HttpClient} used for * Return the {@code HttpAsyncClient} used for
* {@linkplain #createAsyncRequest(URI, HttpMethod) asynchronous execution}. * {@linkplain #createAsyncRequest(URI, HttpMethod) synchronous execution}.
* @since 4.3.10
* @see #getHttpClient()
*/ */
public HttpAsyncClient getAsyncClient() {
return this.asyncClient;
}
/**
* Set the {@code CloseableHttpAsyncClient} used for
* {@linkplain #createAsyncRequest(URI, HttpMethod) asynchronous execution}.
* @deprecated as of 4.3.10, in favor of {@link #setAsyncClient(HttpAsyncClient)}
*/
@Deprecated
public void setHttpAsyncClient(CloseableHttpAsyncClient asyncClient) {
this.asyncClient = asyncClient;
}
/**
* Return the {@code CloseableHttpAsyncClient} used for
* {@linkplain #createAsyncRequest(URI, HttpMethod) asynchronous execution}.
* @deprecated as of 4.3.10, in favor of {@link #getAsyncClient()}
*/
@Deprecated
public CloseableHttpAsyncClient getHttpAsyncClient() { public CloseableHttpAsyncClient getHttpAsyncClient() {
return this.httpAsyncClient; Assert.state(this.asyncClient == null || this.asyncClient instanceof CloseableHttpAsyncClient,
"No CloseableHttpAsyncClient - use getAsyncClient() instead");
return (CloseableHttpAsyncClient) this.asyncClient;
} }
@ -109,22 +159,26 @@ public class HttpComponentsAsyncClientHttpRequestFactory extends HttpComponentsC
} }
private void startAsyncClient() { private void startAsyncClient() {
CloseableHttpAsyncClient asyncClient = getHttpAsyncClient(); HttpAsyncClient asyncClient = getAsyncClient();
if (!asyncClient.isRunning()) { if (asyncClient instanceof CloseableHttpAsyncClient) {
asyncClient.start(); CloseableHttpAsyncClient closeableAsyncClient = (CloseableHttpAsyncClient) asyncClient;
if (!closeableAsyncClient.isRunning()) {
closeableAsyncClient.start();
}
} }
} }
@Override @Override
public AsyncClientHttpRequest createAsyncRequest(URI uri, HttpMethod httpMethod) throws IOException { public AsyncClientHttpRequest createAsyncRequest(URI uri, HttpMethod httpMethod) throws IOException {
HttpAsyncClient asyncClient = getHttpAsyncClient();
startAsyncClient(); startAsyncClient();
HttpUriRequest httpRequest = createHttpUriRequest(httpMethod, uri); HttpUriRequest httpRequest = createHttpUriRequest(httpMethod, uri);
postProcessHttpRequest(httpRequest); postProcessHttpRequest(httpRequest);
HttpContext context = createHttpContext(httpMethod, uri); HttpContext context = createHttpContext(httpMethod, uri);
if (context == null) { if (context == null) {
context = HttpClientContext.create(); context = HttpClientContext.create();
} }
// Request configuration not set in the context // Request configuration not set in the context
if (context.getAttribute(HttpClientContext.REQUEST_CONFIG) == null) { if (context.getAttribute(HttpClientContext.REQUEST_CONFIG) == null) {
// Use request configuration given by the user, when available // Use request configuration given by the user, when available
@ -133,13 +187,14 @@ public class HttpComponentsAsyncClientHttpRequestFactory extends HttpComponentsC
config = ((Configurable) httpRequest).getConfig(); config = ((Configurable) httpRequest).getConfig();
} }
if (config == null) { if (config == null) {
config = createRequestConfig(asyncClient); config = createRequestConfig(getAsyncClient());
} }
if (config != null) { if (config != null) {
context.setAttribute(HttpClientContext.REQUEST_CONFIG, config); context.setAttribute(HttpClientContext.REQUEST_CONFIG, config);
} }
} }
return new HttpComponentsAsyncClientHttpRequest(asyncClient, httpRequest, context);
return new HttpComponentsAsyncClientHttpRequest(getAsyncClient(), httpRequest, context);
} }
@Override @Override
@ -148,7 +203,10 @@ public class HttpComponentsAsyncClientHttpRequestFactory extends HttpComponentsC
super.destroy(); super.destroy();
} }
finally { finally {
getHttpAsyncClient().close(); HttpAsyncClient asyncClient = getAsyncClient();
if (asyncClient instanceof Closeable) {
((Closeable) asyncClient).close();
}
} }
} }

View File

@ -71,7 +71,7 @@ public class HttpComponentsClientHttpRequestFactory implements ClientHttpRequest
* with a default {@link HttpClient}. * with a default {@link HttpClient}.
*/ */
public HttpComponentsClientHttpRequestFactory() { public HttpComponentsClientHttpRequestFactory() {
this(HttpClients.createSystem()); this.httpClient = HttpClients.createSystem();
} }
/** /**
@ -80,8 +80,7 @@ public class HttpComponentsClientHttpRequestFactory implements ClientHttpRequest
* @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(HttpClient httpClient) {
Assert.notNull(httpClient, "HttpClient must not be null"); setHttpClient(httpClient);
this.httpClient = httpClient;
} }
@ -90,6 +89,7 @@ public class HttpComponentsClientHttpRequestFactory implements ClientHttpRequest
* {@linkplain #createRequest(URI, HttpMethod) synchronous execution}. * {@linkplain #createRequest(URI, HttpMethod) synchronous execution}.
*/ */
public void setHttpClient(HttpClient httpClient) { public void setHttpClient(HttpClient httpClient) {
Assert.notNull(httpClient, "HttpClient must not be null");
this.httpClient = httpClient; this.httpClient = httpClient;
} }
@ -97,7 +97,6 @@ public class HttpComponentsClientHttpRequestFactory implements ClientHttpRequest
* Return the {@code HttpClient} used for * Return the {@code HttpClient} used for
* {@linkplain #createRequest(URI, HttpMethod) synchronous execution}. * {@linkplain #createRequest(URI, HttpMethod) synchronous execution}.
*/ */
@Nullable
public HttpClient getHttpClient() { public HttpClient getHttpClient() {
return this.httpClient; return this.httpClient;
} }
@ -153,9 +152,6 @@ public class HttpComponentsClientHttpRequestFactory implements ClientHttpRequest
@Override @Override
public ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod) throws IOException { public ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod) throws IOException {
HttpClient client = getHttpClient();
Assert.state(client != null, "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); HttpContext context = createHttpContext(httpMethod, uri);
@ -171,7 +167,7 @@ public class HttpComponentsClientHttpRequestFactory implements ClientHttpRequest
config = ((Configurable) httpRequest).getConfig(); config = ((Configurable) httpRequest).getConfig();
} }
if (config == null) { if (config == null) {
config = createRequestConfig(client); config = createRequestConfig(getHttpClient());
} }
if (config != null) { if (config != null) {
context.setAttribute(HttpClientContext.REQUEST_CONFIG, config); context.setAttribute(HttpClientContext.REQUEST_CONFIG, config);
@ -179,10 +175,10 @@ public class HttpComponentsClientHttpRequestFactory implements ClientHttpRequest
} }
if (this.bufferRequestBody) { if (this.bufferRequestBody) {
return new HttpComponentsClientHttpRequest(client, httpRequest, context); return new HttpComponentsClientHttpRequest(getHttpClient(), httpRequest, context);
} }
else { else {
return new HttpComponentsStreamingClientHttpRequest(client, httpRequest, context); return new HttpComponentsStreamingClientHttpRequest(getHttpClient(), httpRequest, context);
} }
} }
@ -301,8 +297,9 @@ public class HttpComponentsClientHttpRequestFactory implements ClientHttpRequest
*/ */
@Override @Override
public void destroy() throws Exception { public void destroy() throws Exception {
if (this.httpClient instanceof Closeable) { HttpClient httpClient = getHttpClient();
((Closeable) this.httpClient).close(); if (httpClient instanceof Closeable) {
((Closeable) httpClient).close();
} }
} }
@ -312,7 +309,7 @@ public class HttpComponentsClientHttpRequestFactory implements ClientHttpRequest
* extends {@link org.apache.http.client.methods.HttpEntityEnclosingRequestBase} * extends {@link org.apache.http.client.methods.HttpEntityEnclosingRequestBase}
* rather than {@link org.apache.http.client.methods.HttpRequestBase} and * rather than {@link org.apache.http.client.methods.HttpRequestBase} and
* hence allows HTTP delete with a request body. For use with the RestTemplate * hence allows HTTP delete with a request body. For use with the RestTemplate
* exchange methods which allow the combination of HTTP DELETE with entity. * exchange methods which allow the combination of HTTP DELETE with an entity.
* @since 4.1.2 * @since 4.1.2
*/ */
private static class HttpDelete extends HttpEntityEnclosingRequestBase { private static class HttpDelete extends HttpEntityEnclosingRequestBase {