diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/client/RestClientAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/client/RestClientAutoConfiguration.java
index 1543caa80da..31b7f392441 100644
--- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/client/RestClientAutoConfiguration.java
+++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/client/RestClientAutoConfiguration.java
@@ -36,11 +36,12 @@ import org.springframework.web.client.RestClient;
/**
* {@link EnableAutoConfiguration Auto-configuration} for {@link RestClient}.
*
- * This will produce a {@link org.springframework.web.client.RestClient.Builder
- * RestClient.Builder} bean with the {@code prototype} scope, meaning each injection point
- * will receive a newly cloned instance of the builder.
+ * This will produce a {@link RestClient.Builder RestClient.Builder} bean with the
+ * {@code prototype} scope, meaning each injection point will receive a newly cloned
+ * instance of the builder.
*
* @author Arjen Poutsma
+ * @author Moritz Halbritter
* @since 3.2.0
*/
@AutoConfiguration(after = HttpMessageConvertersAutoConfiguration.class)
@@ -51,19 +52,26 @@ public class RestClientAutoConfiguration {
@Bean
@ConditionalOnMissingBean
@Order(Ordered.LOWEST_PRECEDENCE)
- public HttpMessageConvertersRestClientCustomizer httpMessageConvertersRestClientCustomizer(
+ HttpMessageConvertersRestClientCustomizer httpMessageConvertersRestClientCustomizer(
ObjectProvider messageConverters) {
return new HttpMessageConvertersRestClientCustomizer(messageConverters.getIfUnique());
}
+ @Bean
+ @ConditionalOnMissingBean
+ RestClientBuilderConfigurer restClientBuilderConfigurer(ObjectProvider customizerProvider) {
+ RestClientBuilderConfigurer configurer = new RestClientBuilderConfigurer();
+ configurer.setRestClientCustomizers(customizerProvider.orderedStream().toList());
+ return configurer;
+ }
+
@Bean
@Scope("prototype")
@ConditionalOnMissingBean
- public RestClient.Builder restClientBuilder(ObjectProvider customizerProvider) {
+ RestClient.Builder restClientBuilder(RestClientBuilderConfigurer restClientBuilderConfigurer) {
RestClient.Builder builder = RestClient.builder()
.requestFactory(ClientHttpRequestFactories.get(ClientHttpRequestFactorySettings.DEFAULTS));
- customizerProvider.orderedStream().forEach((customizer) -> customizer.customize(builder));
- return builder;
+ return restClientBuilderConfigurer.configure(builder);
}
}
diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/client/RestClientBuilderConfigurer.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/client/RestClientBuilderConfigurer.java
new file mode 100644
index 00000000000..8d6f57bd461
--- /dev/null
+++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/client/RestClientBuilderConfigurer.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2012-2023 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.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.boot.autoconfigure.web.client;
+
+import java.util.List;
+
+import org.springframework.boot.web.client.RestClientCustomizer;
+import org.springframework.web.client.RestClient;
+import org.springframework.web.client.RestClient.Builder;
+
+/**
+ * Configure {@link RestClient.Builder} with sensible defaults.
+ *
+ * @author Moritz Halbritter
+ * @since 3.2.0
+ */
+public class RestClientBuilderConfigurer {
+
+ private List customizers;
+
+ void setRestClientCustomizers(List customizers) {
+ this.customizers = customizers;
+ }
+
+ /**
+ * Configure the specified {@link RestClient.Builder}. The builder can be further
+ * tuned and default settings can be overridden.
+ * @param builder the {@link RestClient.Builder} instance to configure
+ * @return the configured builder
+ */
+ public RestClient.Builder configure(RestClient.Builder builder) {
+ applyCustomizers(builder);
+ return builder;
+ }
+
+ private void applyCustomizers(Builder builder) {
+ if (this.customizers != null) {
+ for (RestClientCustomizer customizer : this.customizers) {
+ customizer.customize(builder);
+ }
+ }
+ }
+
+}
diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/client/RestClientAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/client/RestClientAutoConfigurationTests.java
index b64a62d1f3c..d2fb90dbf9a 100644
--- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/client/RestClientAutoConfigurationTests.java
+++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/client/RestClientAutoConfigurationTests.java
@@ -32,6 +32,7 @@ import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.test.util.ReflectionTestUtils;
import org.springframework.web.client.RestClient;
+import org.springframework.web.client.RestClient.Builder;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
@@ -42,12 +43,22 @@ import static org.mockito.Mockito.mock;
* Tests for {@link RestClientAutoConfiguration}
*
* @author Arjen Poutsma
+ * @author Moritz Halbritter
*/
class RestClientAutoConfigurationTests {
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(RestClientAutoConfiguration.class));
+ @Test
+ void shouldSupplyBeans() {
+ this.contextRunner.run((context) -> {
+ assertThat(context).hasSingleBean(HttpMessageConvertersRestClientCustomizer.class);
+ assertThat(context).hasSingleBean(RestClientBuilderConfigurer.class);
+ assertThat(context).hasSingleBean(RestClient.Builder.class);
+ });
+ }
+
@Test
void shouldCreateBuilder() {
this.contextRunner.run((context) -> {
@@ -57,6 +68,17 @@ class RestClientAutoConfigurationTests {
});
}
+ @Test
+ void configurerShouldCallCustomizers() {
+ this.contextRunner.withUserConfiguration(RestClientCustomizerConfig.class).run((context) -> {
+ RestClientBuilderConfigurer configurer = context.getBean(RestClientBuilderConfigurer.class);
+ RestClientCustomizer customizer = context.getBean("restClientCustomizer", RestClientCustomizer.class);
+ Builder builder = RestClient.builder();
+ configurer.configure(builder);
+ then(customizer).should().customize(builder);
+ });
+ }
+
@Test
void restClientShouldApplyCustomizers() {
this.contextRunner.withUserConfiguration(RestClientCustomizerConfig.class).run((context) -> {
diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/client/RestClientBuilderConfigurerTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/client/RestClientBuilderConfigurerTests.java
new file mode 100644
index 00000000000..c4c8395c217
--- /dev/null
+++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/client/RestClientBuilderConfigurerTests.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2012-2023 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.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.boot.autoconfigure.web.client;
+
+import java.util.List;
+
+import org.junit.jupiter.api.Test;
+
+import org.springframework.boot.web.client.RestClientCustomizer;
+import org.springframework.web.client.RestClient;
+
+import static org.assertj.core.api.Assertions.assertThatCode;
+import static org.mockito.BDDMockito.then;
+import static org.mockito.Mockito.mock;
+
+/**
+ * Tests for {@link RestClientBuilderConfigurer}.
+ *
+ * @author Moritz Halbritter
+ */
+class RestClientBuilderConfigurerTests {
+
+ @Test
+ void shouldApplyCustomizers() {
+ RestClientBuilderConfigurer configurer = new RestClientBuilderConfigurer();
+ RestClientCustomizer customizer = mock(RestClientCustomizer.class);
+ configurer.setRestClientCustomizers(List.of(customizer));
+ RestClient.Builder builder = RestClient.builder();
+ configurer.configure(builder);
+ then(customizer).should().customize(builder);
+ }
+
+ @Test
+ void shouldSupportNullAsCustomizers() {
+ RestClientBuilderConfigurer configurer = new RestClientBuilderConfigurer();
+ configurer.setRestClientCustomizers(null);
+ assertThatCode(() -> configurer.configure(RestClient.builder())).doesNotThrowAnyException();
+ }
+
+}