diff --git a/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/clientconfig/Http2ClientFeignConfiguration.java b/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/clientconfig/Http2ClientFeignConfiguration.java index f6106375..12db7a0f 100644 --- a/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/clientconfig/Http2ClientFeignConfiguration.java +++ b/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/clientconfig/Http2ClientFeignConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 the original author or authors. + * Copyright 2013-2024 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. @@ -18,8 +18,10 @@ package org.springframework.cloud.openfeign.clientconfig; import java.net.http.HttpClient; import java.time.Duration; +import java.util.List; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.cloud.openfeign.clientconfig.http2client.Http2ClientCustomizer; import org.springframework.cloud.openfeign.support.FeignHttpClientProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -28,18 +30,26 @@ import org.springframework.context.annotation.Configuration; * Default configuration for {@link HttpClient}. * * @author changjin wei(魏昌进) + * @author Luis Duarte */ @Configuration(proxyBeanMethods = false) @ConditionalOnMissingBean(HttpClient.class) public class Http2ClientFeignConfiguration { @Bean - public HttpClient httpClient(FeignHttpClientProperties httpClientProperties) { + @ConditionalOnMissingBean + public HttpClient.Builder httpClientBuilder(FeignHttpClientProperties httpClientProperties) { return HttpClient.newBuilder() .followRedirects(httpClientProperties.isFollowRedirects() ? HttpClient.Redirect.ALWAYS : HttpClient.Redirect.NEVER) .version(HttpClient.Version.valueOf(httpClientProperties.getHttp2().getVersion())) - .connectTimeout(Duration.ofMillis(httpClientProperties.getConnectionTimeout())).build(); + .connectTimeout(Duration.ofMillis(httpClientProperties.getConnectionTimeout())); + } + + @Bean + public HttpClient httpClient(HttpClient.Builder httpClientBuilder, List customizers) { + customizers.forEach(customizer -> customizer.customize(httpClientBuilder)); + return httpClientBuilder.build(); } } diff --git a/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/clientconfig/http2client/Http2ClientCustomizer.java b/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/clientconfig/http2client/Http2ClientCustomizer.java new file mode 100644 index 00000000..2894d7a2 --- /dev/null +++ b/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/clientconfig/http2client/Http2ClientCustomizer.java @@ -0,0 +1,38 @@ +/* + * Copyright 2013-2024 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.cloud.openfeign.clientconfig.http2client; + +import java.net.http.HttpClient; + +/** + * Callback interface that can be implemented by beans wishing to further customize the + * {@link HttpClient} through {@link HttpClient.Builder} retaining its default + * auto-configuration. + * + * @author Luís Duarte + * @since 4.1.1 + */ +@FunctionalInterface +public interface Http2ClientCustomizer { + + /** + * Customize JDK's HttpClient. + * @param builder the HttpClient.Builder to customize + */ + void customize(HttpClient.Builder builder); + +} diff --git a/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/FeignHttp2ClientConfigurationTests.java b/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/FeignHttp2ClientConfigurationTests.java index 89e6022c..875cb9cb 100644 --- a/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/FeignHttp2ClientConfigurationTests.java +++ b/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/FeignHttp2ClientConfigurationTests.java @@ -32,6 +32,7 @@ import static org.assertj.core.api.Assertions.assertThat; /** * @author changjin wei(魏昌进) + * @author Luis Duarte */ class FeignHttp2ClientConfigurationTests { diff --git a/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/test/Http2ClientConfigurationTests.java b/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/test/Http2ClientConfigurationTests.java index d51a0349..8aa2fcd6 100644 --- a/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/test/Http2ClientConfigurationTests.java +++ b/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/test/Http2ClientConfigurationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 the original author or authors. + * Copyright 2013-2024 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. @@ -16,6 +16,8 @@ package org.springframework.cloud.openfeign.test; +import java.net.InetSocketAddress; +import java.net.ProxySelector; import java.net.http.HttpClient; import feign.Client; @@ -27,6 +29,7 @@ import org.springframework.boot.SpringBootConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.cloud.openfeign.clientconfig.http2client.Http2ClientCustomizer; import org.springframework.cloud.openfeign.loadbalancer.FeignBlockingLoadBalancerClient; import org.springframework.context.annotation.Bean; import org.springframework.test.annotation.DirtiesContext; @@ -45,7 +48,8 @@ class Http2ClientConfigurationTests { @Autowired FeignBlockingLoadBalancerClient feignClient; - private static final HttpClient defaultHttpClient = HttpClient.newHttpClient(); + @Autowired + HttpClient underlyingHttpClient; @Test void shouldInstantiateFeignHttp2Client() { @@ -53,7 +57,12 @@ class Http2ClientConfigurationTests { assertThat(delegate instanceof Http2Client).isTrue(); Http2Client http2Client = (Http2Client) delegate; HttpClient httpClient = getField(http2Client, "client"); - assertThat(httpClient).isEqualTo(defaultHttpClient); + assertThat(httpClient).isEqualTo(underlyingHttpClient); + } + + @Test + void customizesHttpClient() { + assertThat(underlyingHttpClient.proxy()).isNotEmpty(); } @SuppressWarnings("unchecked") @@ -72,8 +81,8 @@ class Http2ClientConfigurationTests { static class TestConfig { @Bean - public HttpClient client() { - return defaultHttpClient; + public Http2ClientCustomizer customizer() { + return builder -> builder.proxy(ProxySelector.of(new InetSocketAddress("localhost", 1234))); } }