From 35efdf6b5130f23fb1547b73101b6c73fcf5d238 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Wed, 14 Jun 2017 17:10:44 +0200 Subject: [PATCH] HttpComponentsAsyncClientHttpRequestFactory supports plain HttpAsyncClient as well Issue: SPR-15664 (cherry picked from commit 7b5f96c) --- ...mponentsAsyncClientHttpRequestFactory.java | 108 ++++++++++++++---- ...ttpComponentsClientHttpRequestFactory.java | 25 ++-- 2 files changed, 94 insertions(+), 39 deletions(-) diff --git a/spring-web/src/main/java/org/springframework/http/client/HttpComponentsAsyncClientHttpRequestFactory.java b/spring-web/src/main/java/org/springframework/http/client/HttpComponentsAsyncClientHttpRequestFactory.java index fa57fbd3ca..dc067730d9 100644 --- a/spring-web/src/main/java/org/springframework/http/client/HttpComponentsAsyncClientHttpRequestFactory.java +++ b/spring-web/src/main/java/org/springframework/http/client/HttpComponentsAsyncClientHttpRequestFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2017 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. @@ -16,6 +16,7 @@ package org.springframework.http.client; +import java.io.Closeable; import java.io.IOException; import java.net.URI; @@ -47,7 +48,7 @@ import org.springframework.util.Assert; public class HttpComponentsAsyncClientHttpRequestFactory extends HttpComponentsClientHttpRequestFactory implements AsyncClientHttpRequestFactory, InitializingBean { - private CloseableHttpAsyncClient httpAsyncClient; + private HttpAsyncClient asyncClient; /** @@ -55,49 +56,98 @@ public class HttpComponentsAsyncClientHttpRequestFactory extends HttpComponentsC * with a default {@link HttpAsyncClient} and {@link HttpClient}. */ public HttpComponentsAsyncClientHttpRequestFactory() { - this(HttpAsyncClients.createSystem()); + super(); + this.asyncClient = HttpAsyncClients.createSystem(); } /** * Create a new instance of the {@code HttpComponentsAsyncClientHttpRequestFactory} * 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(); - Assert.notNull(httpAsyncClient, "HttpAsyncClient must not be null"); - this.httpAsyncClient = httpAsyncClient; + setAsyncClient(asyncClient); + } + + /** + * 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} * with the given {@link HttpClient} and {@link HttpAsyncClient} instances. * @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( - CloseableHttpClient httpClient, CloseableHttpAsyncClient httpAsyncClient) { + CloseableHttpClient httpClient, CloseableHttpAsyncClient asyncClient) { super(httpClient); - Assert.notNull(httpAsyncClient, "HttpAsyncClient must not be null"); - this.httpAsyncClient = httpAsyncClient; + setAsyncClient(asyncClient); } /** - * Set the {@code HttpClient} used for - * {@linkplain #createAsyncRequest(URI, HttpMethod) asynchronous execution}. + * Set the {@code HttpAsyncClient} used for + * {@linkplain #createAsyncRequest(URI, HttpMethod) synchronous execution}. + * @since 4.3.10 + * @see #setHttpClient(HttpClient) */ - public void setHttpAsyncClient(CloseableHttpAsyncClient httpAsyncClient) { - this.httpAsyncClient = httpAsyncClient; + public void setAsyncClient(HttpAsyncClient asyncClient) { + Assert.notNull(asyncClient, "HttpAsyncClient must not be null"); + this.asyncClient = asyncClient; } /** - * Return the {@code HttpClient} used for - * {@linkplain #createAsyncRequest(URI, HttpMethod) asynchronous execution}. + * Return the {@code HttpAsyncClient} used for + * {@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() { - return this.httpAsyncClient; + Assert.state(this.asyncClient == null || this.asyncClient instanceof CloseableHttpAsyncClient, + "No CloseableHttpAsyncClient - use getAsyncClient() instead"); + return (CloseableHttpAsyncClient) this.asyncClient; } @@ -107,22 +157,26 @@ public class HttpComponentsAsyncClientHttpRequestFactory extends HttpComponentsC } private void startAsyncClient() { - CloseableHttpAsyncClient asyncClient = getHttpAsyncClient(); - if (!asyncClient.isRunning()) { - asyncClient.start(); + HttpAsyncClient asyncClient = getAsyncClient(); + if (asyncClient instanceof CloseableHttpAsyncClient) { + CloseableHttpAsyncClient closeableAsyncClient = (CloseableHttpAsyncClient) asyncClient; + if (!closeableAsyncClient.isRunning()) { + closeableAsyncClient.start(); + } } } @Override public AsyncClientHttpRequest createAsyncRequest(URI uri, HttpMethod httpMethod) throws IOException { - HttpAsyncClient asyncClient = getHttpAsyncClient(); startAsyncClient(); + 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 @@ -131,13 +185,14 @@ public class HttpComponentsAsyncClientHttpRequestFactory extends HttpComponentsC config = ((Configurable) httpRequest).getConfig(); } if (config == null) { - config = createRequestConfig(asyncClient); + config = createRequestConfig(getAsyncClient()); } if (config != null) { context.setAttribute(HttpClientContext.REQUEST_CONFIG, config); } } - return new HttpComponentsAsyncClientHttpRequest(asyncClient, httpRequest, context); + + return new HttpComponentsAsyncClientHttpRequest(getAsyncClient(), httpRequest, context); } @Override @@ -146,7 +201,10 @@ public class HttpComponentsAsyncClientHttpRequestFactory extends HttpComponentsC super.destroy(); } finally { - getHttpAsyncClient().close(); + HttpAsyncClient asyncClient = getAsyncClient(); + if (asyncClient instanceof Closeable) { + ((Closeable) asyncClient).close(); + } } } diff --git a/spring-web/src/main/java/org/springframework/http/client/HttpComponentsClientHttpRequestFactory.java b/spring-web/src/main/java/org/springframework/http/client/HttpComponentsClientHttpRequestFactory.java index d61231d9d0..e81f9145cc 100644 --- a/spring-web/src/main/java/org/springframework/http/client/HttpComponentsClientHttpRequestFactory.java +++ b/spring-web/src/main/java/org/springframework/http/client/HttpComponentsClientHttpRequestFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2017 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. @@ -85,7 +85,7 @@ public class HttpComponentsClientHttpRequestFactory implements ClientHttpRequest * with a default {@link HttpClient}. */ public HttpComponentsClientHttpRequestFactory() { - this(HttpClients.createSystem()); + this.httpClient = HttpClients.createSystem(); } /** @@ -94,8 +94,7 @@ public class HttpComponentsClientHttpRequestFactory implements ClientHttpRequest * @param httpClient the HttpClient instance to use for this request factory */ public HttpComponentsClientHttpRequestFactory(HttpClient httpClient) { - Assert.notNull(httpClient, "HttpClient must not be null"); - this.httpClient = httpClient; + setHttpClient(httpClient); } @@ -104,6 +103,7 @@ public class HttpComponentsClientHttpRequestFactory implements ClientHttpRequest * {@linkplain #createRequest(URI, HttpMethod) synchronous execution}. */ public void setHttpClient(HttpClient httpClient) { + Assert.notNull(httpClient, "HttpClient must not be null"); this.httpClient = httpClient; } @@ -203,9 +203,6 @@ public class HttpComponentsClientHttpRequestFactory implements ClientHttpRequest @Override 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); postProcessHttpRequest(httpRequest); HttpContext context = createHttpContext(httpMethod, uri); @@ -221,7 +218,7 @@ public class HttpComponentsClientHttpRequestFactory implements ClientHttpRequest config = ((Configurable) httpRequest).getConfig(); } if (config == null) { - config = createRequestConfig(client); + config = createRequestConfig(getHttpClient()); } if (config != null) { context.setAttribute(HttpClientContext.REQUEST_CONFIG, config); @@ -229,10 +226,10 @@ public class HttpComponentsClientHttpRequestFactory implements ClientHttpRequest } if (this.bufferRequestBody) { - return new HttpComponentsClientHttpRequest(client, httpRequest, context); + return new HttpComponentsClientHttpRequest(getHttpClient(), httpRequest, context); } else { - return new HttpComponentsStreamingClientHttpRequest(client, httpRequest, context); + return new HttpComponentsStreamingClientHttpRequest(getHttpClient(), httpRequest, context); } } @@ -269,7 +266,6 @@ public class HttpComponentsClientHttpRequestFactory implements ClientHttpRequest * the factory-level {@link RequestConfig}, if necessary. * @param clientConfig the config held by the current * @return the merged request config - * (may be {@code null} if the given client config is {@code null}) * @since 4.2 */ protected RequestConfig mergeRequestConfig(RequestConfig clientConfig) { @@ -350,8 +346,9 @@ public class HttpComponentsClientHttpRequestFactory implements ClientHttpRequest */ @Override public void destroy() throws Exception { - if (this.httpClient instanceof Closeable) { - ((Closeable) this.httpClient).close(); + HttpClient httpClient = getHttpClient(); + if (httpClient instanceof Closeable) { + ((Closeable) httpClient).close(); } } @@ -361,7 +358,7 @@ public class HttpComponentsClientHttpRequestFactory implements ClientHttpRequest * extends {@link org.apache.http.client.methods.HttpEntityEnclosingRequestBase} * rather than {@link org.apache.http.client.methods.HttpRequestBase} and * 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 */ private static class HttpDelete extends HttpEntityEnclosingRequestBase {