diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/function/client/ClientHttpConnectorAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/function/client/ClientHttpConnectorAutoConfiguration.java index 1a7dde8b92a..c84d217f405 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/function/client/ClientHttpConnectorAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/function/client/ClientHttpConnectorAutoConfiguration.java @@ -41,7 +41,7 @@ import org.springframework.web.reactive.function.client.WebClient; @AutoConfiguration @ConditionalOnClass(WebClient.class) @Import({ ClientHttpConnectorConfiguration.ReactorNetty.class, ClientHttpConnectorConfiguration.JettyClient.class, - ClientHttpConnectorConfiguration.HttpClient5.class }) + ClientHttpConnectorConfiguration.HttpClient5.class, ClientHttpConnectorConfiguration.JdkClient.class }) public class ClientHttpConnectorAutoConfiguration { @Bean diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/function/client/ClientHttpConnectorConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/function/client/ClientHttpConnectorConfiguration.java index c6de185c269..c507af639ac 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/function/client/ClientHttpConnectorConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/function/client/ClientHttpConnectorConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2021 the original author or authors. + * Copyright 2012-2022 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. @@ -31,6 +31,7 @@ import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Lazy; import org.springframework.http.client.reactive.ClientHttpConnector; import org.springframework.http.client.reactive.HttpComponentsClientHttpConnector; +import org.springframework.http.client.reactive.JdkClientHttpConnector; import org.springframework.http.client.reactive.JettyClientHttpConnector; import org.springframework.http.client.reactive.JettyResourceFactory; import org.springframework.http.client.reactive.ReactorClientHttpConnector; @@ -107,4 +108,17 @@ class ClientHttpConnectorConfiguration { } + @Configuration(proxyBeanMethods = false) + @ConditionalOnClass(java.net.http.HttpClient.class) + @ConditionalOnMissingBean(ClientHttpConnector.class) + static class JdkClient { + + @Bean + @Lazy + JdkClientHttpConnector jdkClientHttpConnector() { + return new JdkClientHttpConnector(); + } + + } + } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/reactive/function/client/ClientHttpConnectorAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/reactive/function/client/ClientHttpConnectorAutoConfigurationTests.java index e329138a319..d110b1e1268 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/reactive/function/client/ClientHttpConnectorAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/reactive/function/client/ClientHttpConnectorAutoConfigurationTests.java @@ -16,6 +16,7 @@ package org.springframework.boot.autoconfigure.web.reactive.function.client; +import org.apache.hc.client5.http.impl.async.HttpAsyncClients; import org.eclipse.jetty.reactive.client.ReactiveRequest; import org.junit.jupiter.api.Test; import reactor.netty.http.client.HttpClient; @@ -85,6 +86,21 @@ class ClientHttpConnectorAutoConfigurationTests { }); } + @Test + void whenReactorJettyAndHttpClientBeansAreUnavailableThenJdkClientBeansAreDefined() { + this.contextRunner + .withClassLoader( + new FilteredClassLoader(HttpClient.class, ReactiveRequest.class, HttpAsyncClients.class)) + .run((context) -> { + BeanDefinition customizerDefinition = context.getBeanFactory() + .getBeanDefinition("clientConnectorCustomizer"); + assertThat(customizerDefinition.isLazyInit()).isTrue(); + BeanDefinition connectorDefinition = context.getBeanFactory() + .getBeanDefinition("jdkClientHttpConnector"); + assertThat(connectorDefinition.isLazyInit()).isTrue(); + }); + } + @Test void shouldCreateHttpClientBeans() { this.contextRunner.run((context) -> { diff --git a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/io/rest-client.adoc b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/io/rest-client.adoc index 704897e5ecd..853b956b2a0 100644 --- a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/io/rest-client.adoc +++ b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/io/rest-client.adoc @@ -63,7 +63,7 @@ include::code:MyService[] [[io.rest-client.webclient.runtime]] ==== WebClient Runtime Spring Boot will auto-detect which `ClientHttpConnector` to use to drive `WebClient`, depending on the libraries available on the application classpath. -For now, Reactor Netty, Jetty RS client and Apache HttpClient are supported. +For now, Reactor Netty, Jetty RS client, Apache HttpClient, and the JDK's HttpClient are supported. The `spring-boot-starter-webflux` starter depends on `io.projectreactor.netty:reactor-netty` by default, which brings both server and client implementations. If you choose to use Jetty as a reactive server instead, you should add a dependency on the Jetty Reactive HTTP client library, `org.eclipse.jetty:jetty-reactive-httpclient`.