Changing the default ClientHttpRequestFactory
Since Spring Boot 4, a ClientHttpRequestFactory (built from a ClientHttpRequestFactoryBuilder and HttpClientSettings) is always present in the context, honoring spring.http.clients.* properties and any ClientHttpRequestFactoryBuilderCustomizer registered by the application. The default client-http-request-factory-impl is FROM_CONTEXT: for each REST client, spring-addons-starter-rest reuses that context bean unmodified when no spring-addons-specific customization (proxy, timeouts, disabled SSL certificates validation, protocol version, virtual threads, consumer bean) is required, and enriches a dedicated copy of the context builder (never mutating the shared bean) otherwise. Enrichment is supported when the context builder is HttpComponentsClientHttpRequestFactoryBuilder, JdkClientHttpRequestFactoryBuilder, JettyClientHttpRequestFactoryBuilder, ReactorClientHttpRequestFactoryBuilder or SimpleClientHttpRequestFactoryBuilder; for any other builder type (typically an application-provided of(...)), a RestMisconfigurationException is thrown naming the client and the builder type if customization is actually needed for that client. The Reactor and Simple implementations also reject, with the same exception, whichever customization they cannot honor themselves (see the table below).
client-http-request-factory-impl can also be forced to JDK, HTTP_COMPONENTS, JETTY, REACTOR or SIMPLE: in that case, the context builder is ignored and a fresh instance is always built with the selected implementation, exactly as before Spring Boot 4 introduced auto-configured HTTP client beans.
[!NOTE] If both
ssl-bundleandssl-certificates-validation-enabled: falseare configured for the same client, disabling validation wins: a WARN log names the client and the ignored bundle. The same rule applies on theWebClientside (see SSL bundles).
Three extra properties tune the underlying HTTP client: http-protocol-version forces the HTTP protocol version, use-virtual-threads sets the application task executor (the applicationTaskExecutor bean, virtual-thread when spring.threads.virtual.enabled=true) on the client, and http-client-builder-consumer-bean names a Consumer bean applied to the implementation-specific client builder just before the request factory is built — for whatever is not exposed as properties. Support depends on the implementation, as detailed in the comments below:
com:
c4-soft:
springaddons:
rest:
client:
jdk-sample-client:
http:
# both HTTP_1_1 and HTTP_2 are supported
http-protocol-version: HTTP_2
# requires spring.threads.virtual.enabled to be true
# you probably don't need to set this property as it defaults to ${spring.threads.virtual.enabled}
use-virtual-threads: ${spring.threads.virtual.enabled}
# the name of a Consumer<java.net.http.HttpClient.Builder> bean
http-client-builder-consumer-bean: jdkHttpClientBuilderConsumer
httpcomponents-sample-client:
http:
# requires org.apache.httpcomponents.client5:httpclient5 to be on the class-path
client-http-request-factory-impl: http-components
# these properties are ignored for httpcomponents
http-protocol-version:
use-virtual-threads:
# the name of a Consumer<org.apache.hc.client5.http.impl.classic.HttpClientBuilder> bean
http-client-builder-consumer-bean: httpComponentsHttpClientBuilderConsumer
jetty-sample-client:
http:
# requires org.eclipse.jetty:jetty-client to be on the class-path
client-http-request-factory-impl: jetty
# HTTP_2 also requires org.eclipse.jetty.http2:jetty-http2-client and jetty-http2-client-transport to be on the class-path
http-protocol-version: HTTP_2
use-virtual-threads: ${spring.threads.virtual.enabled}
# the name of a Consumer<org.eclipse.jetty.client.HttpClient> bean
http-client-builder-consumer-bean: jettyHttpClientBuilderConsumer
reactor-sample-client:
http:
# requires io.projectreactor.netty:reactor-netty-http to be on the class-path
# (typically pulled in transitively by spring-boot-starter-webflux)
client-http-request-factory-impl: reactor
# these properties are rejected (RestMisconfigurationException) for reactor: its
# underlying reactor.netty.http.client.HttpClient is immutable, runs on its own
# event-loop threads, and does not expose HTTP protocol version selection here
http-protocol-version:
use-virtual-threads:
http-client-builder-consumer-bean:
simple-sample-client:
http:
# java.net.HttpURLConnection based, always on the class-path
client-http-request-factory-impl: simple
# rejected (RestMisconfigurationException): HttpURLConnection is always HTTP/1.1,
# offers no executor hook, and SimpleClientHttpRequestFactory has no SSL customization hook
ssl-certificates-validation-enabled: true
http-protocol-version:
use-virtual-threads:
# the name of a Consumer<org.springframework.http.client.SimpleClientHttpRequestFactory> bean
http-client-builder-consumer-bean: simpleHttpClientBuilderConsumer
With:
@Bean
Consumer<java.net.http.HttpClient.Builder> jdkHttpClientBuilderConsumer() {
return builder -> { /* TODO: implement */ };
}
@Bean
Consumer<org.apache.hc.client5.http.impl.classic.HttpClientBuilder> httpComponentsHttpClientBuilderConsumer() {
return builder -> { /* TODO: implement */ };
}
@Bean
Consumer<org.eclipse.jetty.client.HttpClient> jettyHttpClientBuilderConsumer() {
return builder -> { /* TODO: implement */ };
}
@Bean
Consumer<org.springframework.http.client.SimpleClientHttpRequestFactory> simpleHttpClientBuilderConsumer() {
return factory -> { /* TODO: implement */ };
}