Skip to content

Commit 983e7b6

Browse files
committed
Introduce ClientHttpConnectorBuilder support
Add a new `ClientHttpConnectorBuilder` interface to support the creation of `ClientHttpConnector` instances. The new code is similar to the `ClientHttpRequestFactoryBuilder` interface that was added to Spring Boot 3.4. The `ClientHttpConnectorBuilder` is a functional interface with additional static factory methods for the various supported `ClientHttpConnector` types. Each type has it's own builder which to support client specific customization. The previous auto-configuration has been relocated to the `org.springframework.boot.autoconfigure.http.client.reactive` package and updated to make use of the builder. Closes gh-43079
1 parent 4034725 commit 983e7b6

File tree

68 files changed

+3682
-1182
lines changed

Some content is hidden

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

68 files changed

+3682
-1182
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
/*
2+
* Copyright 2012-2025 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.autoconfigure.http.client;
18+
19+
import java.time.Duration;
20+
21+
import org.springframework.beans.factory.ObjectProvider;
22+
import org.springframework.boot.http.client.HttpClientSettings;
23+
import org.springframework.boot.http.client.HttpRedirects;
24+
import org.springframework.boot.ssl.SslBundle;
25+
import org.springframework.boot.ssl.SslBundles;
26+
import org.springframework.util.StringUtils;
27+
28+
/**
29+
* Abstract base class for properties that directly or indirectly make use of a blocking
30+
* or reactive HTTP client.
31+
*
32+
* @author Phillip Webb
33+
* @since 3.5.0
34+
* @see HttpClientSettings
35+
*/
36+
public abstract class AbstractHttpClientProperties {
37+
38+
/**
39+
* Handling for HTTP redirects.
40+
*/
41+
private HttpRedirects redirects = HttpRedirects.FOLLOW_WHEN_POSSIBLE;
42+
43+
/**
44+
* Default connect timeout for a client HTTP request.
45+
*/
46+
private Duration connectTimeout;
47+
48+
/**
49+
* Default read timeout for a client HTTP request.
50+
*/
51+
private Duration readTimeout;
52+
53+
/**
54+
* Default SSL configuration for a client HTTP request.
55+
*/
56+
private final Ssl ssl = new Ssl();
57+
58+
public HttpRedirects getRedirects() {
59+
return this.redirects;
60+
}
61+
62+
public void setRedirects(HttpRedirects redirects) {
63+
this.redirects = redirects;
64+
}
65+
66+
public Duration getConnectTimeout() {
67+
return this.connectTimeout;
68+
}
69+
70+
public void setConnectTimeout(Duration connectTimeout) {
71+
this.connectTimeout = connectTimeout;
72+
}
73+
74+
public Duration getReadTimeout() {
75+
return this.readTimeout;
76+
}
77+
78+
public void setReadTimeout(Duration readTimeout) {
79+
this.readTimeout = readTimeout;
80+
}
81+
82+
public Ssl getSsl() {
83+
return this.ssl;
84+
}
85+
86+
/**
87+
* Return {@link HttpClientSettings} based on these properties.
88+
* @param sslBundles a {@link SslBundles} provider
89+
* @return the {@link HttpClientSettings}
90+
*/
91+
protected HttpClientSettings httpClientSettings(ObjectProvider<SslBundles> sslBundles) {
92+
return new HttpClientSettings(this.redirects, this.connectTimeout, this.readTimeout, sslBundle(sslBundles));
93+
}
94+
95+
private SslBundle sslBundle(ObjectProvider<SslBundles> sslBundles) {
96+
String name = getSsl().getBundle();
97+
return (StringUtils.hasLength(name)) ? sslBundles.getObject().getBundle(name) : null;
98+
}
99+
100+
/**
101+
* SSL configuration.
102+
*/
103+
public static class Ssl {
104+
105+
/**
106+
* SSL bundle to use.
107+
*/
108+
private String bundle;
109+
110+
public String getBundle() {
111+
return this.bundle;
112+
}
113+
114+
public void setBundle(String bundle) {
115+
this.bundle = bundle;
116+
}
117+
118+
}
119+
120+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
/*
2+
* Copyright 2012-2025 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.autoconfigure.http.client;
18+
19+
import java.util.function.Supplier;
20+
21+
import org.springframework.boot.context.properties.ConfigurationProperties;
22+
import org.springframework.boot.http.client.ClientHttpRequestFactoryBuilder;
23+
import org.springframework.boot.http.client.ClientHttpRequestFactorySettings;
24+
import org.springframework.http.client.ClientHttpRequestFactory;
25+
26+
/**
27+
* Base {@link ConfigurationProperties @ConfigurationProperties} for configuring a
28+
* {@link ClientHttpRequestFactory}.
29+
*
30+
* @author Phillip Webb
31+
* @since 3.5.0
32+
* @see ClientHttpRequestFactorySettings
33+
*/
34+
public abstract class AbstractHttpRequestFactoryProperties extends AbstractHttpClientProperties {
35+
36+
/**
37+
* Default factory used for a client HTTP request.
38+
*/
39+
private Factory factory;
40+
41+
public Factory getFactory() {
42+
return this.factory;
43+
}
44+
45+
public void setFactory(Factory factory) {
46+
this.factory = factory;
47+
}
48+
49+
/**
50+
* Return a {@link ClientHttpRequestFactoryBuilder} based on the properties.
51+
* @return a {@link ClientHttpRequestFactoryBuilder}
52+
*/
53+
protected final ClientHttpRequestFactoryBuilder<?> factoryBuilder() {
54+
Factory factory = getFactory();
55+
return (factory != null) ? factory.builder() : ClientHttpRequestFactoryBuilder.detect();
56+
}
57+
58+
/**
59+
* Supported factory types.
60+
*/
61+
public enum Factory {
62+
63+
/**
64+
* Apache HttpComponents HttpClient.
65+
*/
66+
HTTP_COMPONENTS(ClientHttpRequestFactoryBuilder::httpComponents),
67+
68+
/**
69+
* Jetty's HttpClient.
70+
*/
71+
JETTY(ClientHttpRequestFactoryBuilder::jetty),
72+
73+
/**
74+
* Reactor-Netty.
75+
*/
76+
REACTOR(ClientHttpRequestFactoryBuilder::reactor),
77+
78+
/**
79+
* Java's HttpClient.
80+
*/
81+
JDK(ClientHttpRequestFactoryBuilder::jdk),
82+
83+
/**
84+
* Standard JDK facilities.
85+
*/
86+
SIMPLE(ClientHttpRequestFactoryBuilder::simple);
87+
88+
private final Supplier<ClientHttpRequestFactoryBuilder<?>> builderSupplier;
89+
90+
Factory(Supplier<ClientHttpRequestFactoryBuilder<?>> builderSupplier) {
91+
this.builderSupplier = builderSupplier;
92+
}
93+
94+
ClientHttpRequestFactoryBuilder<?> builder() {
95+
return this.builderSupplier.get();
96+
}
97+
98+
}
99+
100+
}

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/http/client/HttpClientAutoConfiguration.java

+14-12
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2024 the original author or authors.
2+
* Copyright 2012-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -21,17 +21,17 @@
2121
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
2222
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
2323
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
24-
import org.springframework.boot.autoconfigure.http.client.HttpClientProperties.Factory;
2524
import org.springframework.boot.autoconfigure.ssl.SslAutoConfiguration;
2625
import org.springframework.boot.context.properties.EnableConfigurationProperties;
2726
import org.springframework.boot.http.client.ClientHttpRequestFactoryBuilder;
2827
import org.springframework.boot.http.client.ClientHttpRequestFactorySettings;
29-
import org.springframework.boot.ssl.SslBundle;
28+
import org.springframework.boot.http.client.ClientHttpRequestFactorySettings.Redirects;
29+
import org.springframework.boot.http.client.HttpClientSettings;
30+
import org.springframework.boot.http.client.HttpRedirects;
3031
import org.springframework.boot.ssl.SslBundles;
3132
import org.springframework.context.annotation.Bean;
3233
import org.springframework.context.annotation.Conditional;
3334
import org.springframework.http.client.ClientHttpRequestFactory;
34-
import org.springframework.util.StringUtils;
3535

3636
/**
3737
* {@link EnableAutoConfiguration Auto-configuration} for
@@ -49,22 +49,24 @@ public class HttpClientAutoConfiguration {
4949
@Bean
5050
@ConditionalOnMissingBean
5151
ClientHttpRequestFactoryBuilder<?> clientHttpRequestFactoryBuilder(HttpClientProperties httpClientProperties) {
52-
Factory factory = httpClientProperties.getFactory();
53-
return (factory != null) ? factory.builder() : ClientHttpRequestFactoryBuilder.detect();
52+
return httpClientProperties.factoryBuilder();
5453
}
5554

5655
@Bean
5756
@ConditionalOnMissingBean
5857
ClientHttpRequestFactorySettings clientHttpRequestFactorySettings(HttpClientProperties httpClientProperties,
5958
ObjectProvider<SslBundles> sslBundles) {
60-
SslBundle sslBundle = getSslBundle(httpClientProperties.getSsl(), sslBundles);
61-
return new ClientHttpRequestFactorySettings(httpClientProperties.getRedirects(),
62-
httpClientProperties.getConnectTimeout(), httpClientProperties.getReadTimeout(), sslBundle);
59+
HttpClientSettings settings = httpClientProperties.httpClientSettings(sslBundles);
60+
return new ClientHttpRequestFactorySettings(asRequestFactoryRedirects(settings.redirects()),
61+
settings.connectTimeout(), settings.readTimeout(), settings.sslBundle());
6362
}
6463

65-
private SslBundle getSslBundle(HttpClientProperties.Ssl properties, ObjectProvider<SslBundles> sslBundles) {
66-
String name = properties.getBundle();
67-
return (StringUtils.hasLength(name)) ? sslBundles.getObject().getBundle(name) : null;
64+
private Redirects asRequestFactoryRedirects(HttpRedirects redirects) {
65+
return switch (redirects) {
66+
case FOLLOW_WHEN_POSSIBLE -> Redirects.FOLLOW_WHEN_POSSIBLE;
67+
case FOLLOW -> Redirects.FOLLOW;
68+
case DONT_FOLLOW -> Redirects.DONT_FOLLOW;
69+
};
6870
}
6971

7072
}

0 commit comments

Comments
 (0)