Skip to content

Commit 02b2d03

Browse files
committed
Rationalize HTTP client configuration properties
Simplify HTTP client configuration properties by sharing common settings for both blocking and reactive clients. The `ClientHttpRequestFactorySettings` and `ClientHttpConnectorSettings` have been merged to a single `HttpClientSettings` class. Properties to configure common settings are available under: `spring.http.clients` Blocking and reactive settings have been moved to `spring.http.clients.blocking` and `spring.http.clients.reactive`. With currently only the factory/connector being configurable. HTTP Service Client properties have also been rationalized under a `spring.http.serviceclient.<group-name>`. Support for properties that apply to all service clients and all Rest/Web Clients have been removed. Support for `ApiVerionInserter` beans has also been removed in favor of configuring the service group or builders directly. Closes gh-47398
1 parent f4e8cac commit 02b2d03

File tree

108 files changed

+1617
-2902
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

108 files changed

+1617
-2902
lines changed

documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/io/rest-client.adoc

Lines changed: 57 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -55,29 +55,19 @@ You can learn more about the {url-spring-framework-docs}/web/webflux-webclient/c
5555
[[io.rest-client.webclient.configuration]]
5656
=== Global HTTP Connector Configuration
5757

58-
If the auto-detected javadoc:org.springframework.http.client.reactive.ClientHttpConnector[] does not meet your needs, you can use the configprop:spring.http.reactiveclient.connector[] property to pick a specific connector.
58+
If the auto-detected javadoc:org.springframework.http.client.reactive.ClientHttpConnector[] does not meet your needs, you can use the configprop:spring.http.clients.reactive.connector[] property to pick a specific connector.
5959
For example, if you have Reactor Netty on your classpath, but you prefer Jetty's javadoc:org.eclipse.jetty.client.HttpClient[] you can add the following:
6060

6161
[configprops,yaml]
6262
----
6363
spring:
6464
http:
65-
reactiveclient:
66-
connector: jetty
65+
clients:
66+
reactive:
67+
connector: jetty
6768
----
6869

69-
You can also set properties to change defaults that will be applied to all reactive connectors.
70-
For example, you may want to change timeouts and if redirects are followed:
71-
72-
[configprops,yaml]
73-
----
74-
spring:
75-
http:
76-
reactiveclient:
77-
connect-timeout: 2s
78-
read-timeout: 1s
79-
redirects: dont-follow
80-
----
70+
TIP: You can also use xref:io/rest-client.adoc#io.rest-client.global-configuration[global configuration properties] which apply to all HTTP clients.
8171

8272
For more complex customizations, you can use javadoc:org.springframework.boot.http.client.autoconfigure.reactive.ClientHttpConnectorBuilderCustomizer[] or declare your own javadoc:org.springframework.boot.http.client.reactive.ClientHttpConnectorBuilder[] bean which will cause auto-configuration to back off.
8373
This can be useful when you need to customize some of the internals of the underlying HTTP library.
@@ -88,7 +78,6 @@ include-code::MyConnectorHttpConfiguration[]
8878

8979

9080

91-
9281
[[io.rest-client.webclient.customization]]
9382
=== WebClient Customization
9483

@@ -246,29 +235,19 @@ If multiple clients are available on the classpath, and not global configuration
246235
[[io.rest-client.clienthttprequestfactory.configuration]]
247236
=== Global HTTP Client Configuration
248237

249-
If the auto-detected HTTP client does not meet your needs, you can use the configprop:spring.http.client.factory[] property to pick a specific factory.
238+
If the auto-detected HTTP client does not meet your needs, you can use the configprop:spring.http.clients.blocking.factory[] property to pick a specific factory.
250239
For example, if you have Apache HttpClient on your classpath, but you prefer Jetty's javadoc:org.eclipse.jetty.client.HttpClient[] you can add the following:
251240

252241
[configprops,yaml]
253242
----
254243
spring:
255244
http:
256-
client:
257-
factory: jetty
245+
clients:
246+
blocking:
247+
factory: jetty
258248
----
259249

260-
You can also set properties to change defaults that will be applied to all clients.
261-
For example, you may want to change timeouts and if redirects are followed:
262-
263-
[configprops,yaml]
264-
----
265-
spring:
266-
http:
267-
client:
268-
connect-timeout: 2s
269-
read-timeout: 1s
270-
redirects: dont-follow
271-
----
250+
TIP: You can also use xref:io/rest-client.adoc#io.rest-client.global-configuration[global configuration properties] which apply to all HTTP clients.
272251

273252
For more complex customizations, you can use javadoc:org.springframework.boot.http.client.autoconfigure.ClientHttpRequestFactoryBuilderCustomizer[] or declare your own javadoc:org.springframework.boot.http.client.ClientHttpRequestFactoryBuilder[] bean which will cause auto-configuration to back off.
274253
This can be useful when you need to customize some of the internals of the underlying HTTP library.
@@ -286,23 +265,6 @@ Both `WebClient` and `RestClient` support making versioned remote HTTP calls so
286265
Commonly this involves sending an HTTP header, a query parameter or URL path segment that indicates the version of the API that should be used.
287266

288267
You can configure API versioning using methods on `WebClient.Builder` or `RestClient.Builder`.
289-
You can also the `spring.http.reactiveclient.webclient.apiversion` or `spring.http.client.restclient.apiversion` properties if you want to apply the same configuration to all builders.
290-
291-
For example, the following adds an `X-Version` HTTP header to all calls from the `RestClient` and uses the version `1.0.0` unless overridden for specific requests:
292-
293-
[configprops,yaml]
294-
----
295-
spring:
296-
http:
297-
client:
298-
restclient:
299-
apiversion:
300-
default: 1.0.0
301-
insert:
302-
header: X-Version
303-
----
304-
305-
You can also define javadoc:org.springframework.web.client.ApiVersionInserter[] and javadoc:org.springframework.web.client.ApiVersionFormatter[] beans if you need more control of the way that version information should be inserted and formatted.
306268

307269
TIP: API versioning is also supported on the server-side.
308270
See the xref:web/servlet.adoc#web.servlet.spring-mvc.api-versioning[Spring MVC] and xref:web/reactive.adoc#web.reactive.webflux.api-versioning[Spring WebFlux] sections for details.
@@ -363,32 +325,15 @@ We can then write:
363325

364326
include-code::MyApplication[]
365327

366-
And finally we can then use a `base-url` property to link the `echo` group to an actual URL.
367-
368-
For a `RestClient` backed HTTP Service client this would be:
328+
And finally we can then use a `base-url` property to link the `echo` group to an actual URL:
369329

370330
[configprops,yaml]
371331
----
372332
spring:
373333
http:
374-
client:
375-
service:
376-
group:
377-
echo:
378-
base-url: "https://echo.zuplo.io"
379-
----
380-
381-
For a `WebClient` backed HTTP Service client, we'd use the reactive variant:
382-
383-
[configprops,yaml]
384-
----
385-
spring:
386-
http:
387-
reactiveclient:
388-
service:
389-
group:
390-
echo:
391-
base-url: "https://echo.zuplo.io"
334+
serviceclient:
335+
echo:
336+
base-url: "https://echo.zuplo.io"
392337
----
393338

394339
TIP: HTTP Service clients will be associated with a group named "`default`" if you don't specify a group.
@@ -408,7 +353,7 @@ include-code::repeat/MyApplication[]
408353
[[io.rest-client.httpservice.properties]]
409354
=== Configuration Properties
410355

411-
Configuration properties for HTTP Services can be specified under `spring.http.client.service` for `RestClient` backed clients and `spring.http.reactiveclient.service` for `WebClient` backed clients.
356+
Configuration properties for HTTP Services can be specified under `spring.http.serviceclient.<group-name>`:
412357

413358
You can use properties to configure aspects such as:
414359

@@ -419,26 +364,30 @@ You can use properties to configure aspects such as:
419364
* Connection and read timeouts.
420365
* SSL bundles to use.
421366

422-
Properties are hierarchical and can be specified per-group, or for all HTTP Service clients.
423-
Some properties can also be specified as xref:/io/rest-client.adoc#io.rest-client.clienthttprequestfactory.configuration[global client configuration], so that they are considered for both HTTP Service clients and direct use of `RestClient` or `WebClient`.
367+
TIP: You can also use xref:io/rest-client.adoc#io.rest-client.global-configuration[global configuration properties] which apply to all HTTP clients.
424368

425369
For example, the properties below will:
426370

427-
* Configure all HTTP Service client and `RestClient` beans to use a one second connect timeout (unless otherwise overridden).
428-
* Configure all HTTP Service clients to use a two second read timeout (unless otherwise overridden).
429-
* Configure HTTP Service clients in the "`echo`" group to use a specific base URL.
371+
* Configure all HTTP clients to use a one second connect timeout (unless otherwise overridden).
372+
* Configure HTTP Service clients in the "`echo`" group to:
373+
** Use a specific base URL.
374+
** Have a two second read timeout.
375+
** Insert API version information using an `X-Version` header.
430376

431377
[configprops,yaml]
432378
----
433379
spring:
434380
http:
435-
client:
381+
clients:
436382
connect-timeout: 1s
437-
service:
383+
serviceclient:
384+
echo:
385+
base-url: "https://echo.zuplo.io"
438386
read-timeout: 2s;
439-
group:
440-
echo:
441-
base-url: "https://echo.zuplo.io"
387+
apiversion:
388+
default: 1.0.0
389+
insert:
390+
header: X-Version
442391
----
443392

444393

@@ -466,3 +415,31 @@ You can javadoc:org.springframework.context.annotation.Import[format=annotation]
466415
For more details, see {url-spring-framework-docs}/integration/rest-clients.html#rest-http-service-client-group-config[Spring Framework reference documentation].
467416

468417
Regardless of which method you use to register HTTP Service clients, Spring Boot's support remains the same.
418+
419+
420+
421+
[[io.rest-client.global-configuration]]
422+
== Applying Global Configuration to All HTTP Clients
423+
424+
Regardless of the underlying technology being used, all HTTP clients have common settings that can be configured.
425+
426+
These include:
427+
428+
* Connection Timeouts.
429+
* Read Timeouts.
430+
* How HTTP redirects should be handled.
431+
* Which SSL bundle should be used when connecting.
432+
433+
These common settings are represented by the javadoc:org.springframework.boot.http.client.HttpClientSettings[] class which can be passed into the `build(...)` methods of javadoc:org.springframework.boot.http.client.reactive.ClientHttpConnectorBuilder[] and javadoc:org.springframework.boot.http.client.ClientHttpRequestFactoryBuilder[].
434+
435+
If you want to apply the same configuration to all auto-configured clients, you can use `spring.http.clients` properties to do so:
436+
437+
[configprops,yaml]
438+
----
439+
spring:
440+
http:
441+
clients:
442+
connect-timeout: 2s
443+
read-timeout: 1s
444+
redirects: dont-follow
445+
----

documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/io/restclient/restclient/ssl/settings/MyService.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
import java.time.Duration;
2020

2121
import org.springframework.boot.http.client.ClientHttpRequestFactoryBuilder;
22-
import org.springframework.boot.http.client.ClientHttpRequestFactorySettings;
22+
import org.springframework.boot.http.client.HttpClientSettings;
2323
import org.springframework.boot.ssl.SslBundles;
2424
import org.springframework.http.client.ClientHttpRequestFactory;
2525
import org.springframework.stereotype.Service;
@@ -31,8 +31,7 @@ public class MyService {
3131
private final RestClient restClient;
3232

3333
public MyService(RestClient.Builder restClientBuilder, SslBundles sslBundles) {
34-
ClientHttpRequestFactorySettings settings = ClientHttpRequestFactorySettings
35-
.ofSslBundle(sslBundles.getBundle("mybundle"))
34+
HttpClientSettings settings = HttpClientSettings.ofSslBundle(sslBundles.getBundle("mybundle"))
3635
.withReadTimeout(Duration.ofMinutes(2));
3736
ClientHttpRequestFactory requestFactory = ClientHttpRequestFactoryBuilder.detect().build(settings);
3837
this.restClient = restClientBuilder.baseUrl("https://example.org").requestFactory(requestFactory).build();

documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/io/webservices/template/MyWebServiceTemplateConfiguration.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818

1919
import java.time.Duration;
2020

21-
import org.springframework.boot.http.client.ClientHttpRequestFactorySettings;
21+
import org.springframework.boot.http.client.HttpClientSettings;
2222
import org.springframework.boot.webservices.client.WebServiceMessageSenderFactory;
2323
import org.springframework.boot.webservices.client.WebServiceTemplateBuilder;
2424
import org.springframework.context.annotation.Bean;
@@ -30,7 +30,7 @@ public class MyWebServiceTemplateConfiguration {
3030

3131
@Bean
3232
public WebServiceTemplate webServiceTemplate(WebServiceTemplateBuilder builder) {
33-
ClientHttpRequestFactorySettings settings = ClientHttpRequestFactorySettings.defaults()
33+
HttpClientSettings settings = HttpClientSettings.defaults()
3434
.withConnectTimeout(Duration.ofSeconds(2))
3535
.withReadTimeout(Duration.ofSeconds(2));
3636
builder.httpMessageSenderFactory(WebServiceMessageSenderFactory.http(settings));

documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/io/restclient/restclient/ssl/settings/MyService.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
package org.springframework.boot.docs.io.restclient.restclient.ssl.settings
1818

1919
import org.springframework.boot.http.client.ClientHttpRequestFactoryBuilder;
20-
import org.springframework.boot.http.client.ClientHttpRequestFactorySettings;
20+
import org.springframework.boot.http.client.HttpClientSettings
2121
import org.springframework.boot.ssl.SslBundles
2222
import org.springframework.stereotype.Service
2323
import org.springframework.web.client.RestClient
@@ -29,7 +29,7 @@ class MyService(restClientBuilder: RestClient.Builder, sslBundles: SslBundles) {
2929
private val restClient: RestClient
3030

3131
init {
32-
val settings = ClientHttpRequestFactorySettings.defaults()
32+
val settings = HttpClientSettings.defaults()
3333
.withReadTimeout(Duration.ofMinutes(2))
3434
.withSslBundle(sslBundles.getBundle("mybundle"))
3535
val requestFactory = ClientHttpRequestFactoryBuilder.detect().build(settings);

documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/io/webservices/template/MyWebServiceTemplateConfiguration.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

1717
package org.springframework.boot.docs.io.webservices.template
1818

19-
import org.springframework.boot.http.client.ClientHttpRequestFactorySettings
19+
import org.springframework.boot.http.client.HttpClientSettings
2020
import org.springframework.boot.webservices.client.WebServiceMessageSenderFactory
2121
import org.springframework.boot.webservices.client.WebServiceTemplateBuilder
2222
import org.springframework.context.annotation.Bean
@@ -29,7 +29,7 @@ class MyWebServiceTemplateConfiguration {
2929

3030
@Bean
3131
fun webServiceTemplate(builder: WebServiceTemplateBuilder): WebServiceTemplate {
32-
val settings = ClientHttpRequestFactorySettings.defaults()
32+
val settings = HttpClientSettings.defaults()
3333
.withConnectTimeout(Duration.ofSeconds(2))
3434
.withReadTimeout(Duration.ofSeconds(2))
3535
builder.httpMessageSenderFactory(WebServiceMessageSenderFactory.http(settings))

module/spring-boot-http-client/src/main/java/org/springframework/boot/http/client/AbstractClientHttpRequestFactoryBuilder.java

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@
2626

2727
import org.springframework.boot.util.LambdaSafe;
2828
import org.springframework.http.client.ClientHttpRequestFactory;
29-
import org.springframework.lang.Contract;
3029
import org.springframework.util.Assert;
3130

3231
/**
@@ -67,20 +66,12 @@ private <E> List<E> merge(Collection<E> list, Collection<? extends E> additional
6766

6867
@Override
6968
@SuppressWarnings("unchecked")
70-
public final T build(@Nullable ClientHttpRequestFactorySettings settings) {
71-
T factory = createClientHttpRequestFactory(
72-
(settings != null) ? settings : ClientHttpRequestFactorySettings.defaults());
69+
public final T build(@Nullable HttpClientSettings settings) {
70+
T factory = createClientHttpRequestFactory((settings != null) ? settings : HttpClientSettings.defaults());
7371
LambdaSafe.callbacks(Consumer.class, this.customizers, factory).invoke((consumer) -> consumer.accept(factory));
7472
return factory;
7573
}
7674

77-
protected abstract T createClientHttpRequestFactory(ClientHttpRequestFactorySettings settings);
78-
79-
@Contract("!null -> !null")
80-
protected final @Nullable HttpClientSettings asHttpClientSettings(
81-
@Nullable ClientHttpRequestFactorySettings settings) {
82-
return (settings != null) ? new HttpClientSettings(settings.redirects(), settings.connectTimeout(),
83-
settings.readTimeout(), settings.sslBundle()) : null;
84-
}
75+
protected abstract T createClientHttpRequestFactory(HttpClientSettings settings);
8576

8677
}

module/spring-boot-http-client/src/main/java/org/springframework/boot/http/client/ClientHttpRequestFactoryBuilder.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ default T build() {
6161
* @param settings the settings to apply or {@code null}
6262
* @return a fully configured {@link ClientHttpRequestFactory}.
6363
*/
64-
T build(@Nullable ClientHttpRequestFactorySettings settings);
64+
T build(@Nullable HttpClientSettings settings);
6565

6666
/**
6767
* Return a new {@link ClientHttpRequestFactoryBuilder} that applies the given
@@ -175,7 +175,7 @@ static <T extends ClientHttpRequestFactory> ClientHttpRequestFactoryBuilder<T> o
175175

176176
/**
177177
* Return a new {@link ClientHttpRequestFactoryBuilder} from the given supplier, using
178-
* reflection to ultimately apply the {@link ClientHttpRequestFactorySettings}.
178+
* reflection to ultimately apply the {@link HttpClientSettings}.
179179
* @param <T> the {@link ClientHttpRequestFactory} type
180180
* @param requestFactorySupplier the {@link ClientHttpRequestFactory} supplier
181181
* @return a new {@link ClientHttpRequestFactoryBuilder}

0 commit comments

Comments
 (0)