Add HttpClientBuilderCustomizer interface (#890)
In addition to leveraging existing Spring Cloud settings, provide the ability for a user to customize settings.
This commit is contained in:
@@ -139,6 +139,7 @@ The OkHttpClient, Apache HttpClient 5 and Http2Client Feign clients can be used
|
||||
You can customize the HTTP client used by providing a bean of either `org.apache.hc.client5.http.impl.classic.CloseableHttpClient` when using Apache HC5.
|
||||
|
||||
You can further customise http clients by setting values in the `spring.cloud.openfeign.httpclient.xxx` properties. The ones prefixed just with `httpclient` will work for all the clients, the ones prefixed with `httpclient.hc5` to Apache HttpClient 5, the ones prefixed with `httpclient.okhttp` to OkHttpClient and the ones prefixed with `httpclient.http2` to Http2Client. You can find a full list of properties you can customise in the appendix.
|
||||
If you can not configure Apache HttpClient 5 by using properties, there is an `HttpClientBuilderCustomizer` interface for programmatic configuration.
|
||||
|
||||
TIP: Starting with Spring Cloud OpenFeign 4, the Feign Apache HttpClient 4 is no longer supported. We suggest using Apache HttpClient 5 instead.
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2022 the original author or authors.
|
||||
* Copyright 2013-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.
|
||||
@@ -20,6 +20,7 @@ import java.security.KeyManagementException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.SecureRandom;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.net.ssl.SSLContext;
|
||||
@@ -31,6 +32,7 @@ import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.apache.hc.client5.http.config.RequestConfig;
|
||||
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
|
||||
import org.apache.hc.client5.http.impl.classic.HttpClientBuilder;
|
||||
import org.apache.hc.client5.http.impl.classic.HttpClients;
|
||||
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder;
|
||||
import org.apache.hc.client5.http.io.HttpClientConnectionManager;
|
||||
@@ -46,6 +48,7 @@ import org.apache.hc.core5.ssl.SSLContexts;
|
||||
import org.apache.hc.core5.util.TimeValue;
|
||||
import org.apache.hc.core5.util.Timeout;
|
||||
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.cloud.openfeign.support.FeignHttpClientProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
@@ -56,6 +59,7 @@ import org.springframework.context.annotation.Configuration;
|
||||
*
|
||||
* @author Nguyen Ky Thanh
|
||||
* @author changjin wei(魏昌进)
|
||||
* @author Kwangyong Kim
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnMissingBean(CloseableHttpClient.class)
|
||||
@@ -85,18 +89,23 @@ public class HttpClient5FeignConfiguration {
|
||||
|
||||
@Bean
|
||||
public CloseableHttpClient httpClient5(HttpClientConnectionManager connectionManager,
|
||||
FeignHttpClientProperties httpClientProperties) {
|
||||
httpClient5 = HttpClients.custom().disableCookieManagement().useSystemProperties()
|
||||
.setConnectionManager(connectionManager).evictExpiredConnections()
|
||||
.setDefaultRequestConfig(RequestConfig.custom()
|
||||
.setConnectTimeout(
|
||||
Timeout.of(httpClientProperties.getConnectionTimeout(), TimeUnit.MILLISECONDS))
|
||||
.setRedirectsEnabled(httpClientProperties.isFollowRedirects())
|
||||
.setConnectionRequestTimeout(
|
||||
Timeout.of(httpClientProperties.getHc5().getConnectionRequestTimeout(),
|
||||
httpClientProperties.getHc5().getConnectionRequestTimeoutUnit()))
|
||||
.build())
|
||||
.build();
|
||||
FeignHttpClientProperties httpClientProperties,
|
||||
ObjectProvider<List<HttpClientBuilderCustomizer>> customizerProvider) {
|
||||
HttpClientBuilder httpClientBuilder = HttpClients.custom().disableCookieManagement().useSystemProperties()
|
||||
.setConnectionManager(connectionManager).evictExpiredConnections()
|
||||
.setDefaultRequestConfig(RequestConfig.custom()
|
||||
.setConnectTimeout(
|
||||
Timeout.of(httpClientProperties.getConnectionTimeout(), TimeUnit.MILLISECONDS))
|
||||
.setRedirectsEnabled(httpClientProperties.isFollowRedirects())
|
||||
.setConnectionRequestTimeout(
|
||||
Timeout.of(httpClientProperties.getHc5().getConnectionRequestTimeout(),
|
||||
httpClientProperties.getHc5().getConnectionRequestTimeoutUnit()))
|
||||
.build());
|
||||
|
||||
customizerProvider.getIfAvailable(List::of)
|
||||
.forEach(c -> c.customize(httpClientBuilder));
|
||||
|
||||
httpClient5 = httpClientBuilder.build();
|
||||
return httpClient5;
|
||||
}
|
||||
|
||||
@@ -146,4 +155,19 @@ public class HttpClient5FeignConfiguration {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback interface that customize {@link HttpClientBuilder} objects before HttpClient created.
|
||||
*
|
||||
* @author Kwangyong Kim
|
||||
* @since 4.1.0
|
||||
*/
|
||||
public interface HttpClientBuilderCustomizer {
|
||||
|
||||
/**
|
||||
* Customize HttpClientBuilder.
|
||||
* @param builder the {@code HttpClientBuilder} to customize
|
||||
*/
|
||||
void customize(HttpClientBuilder builder);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2022 the original author or authors.
|
||||
* Copyright 2013-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.
|
||||
@@ -19,21 +19,29 @@ package org.springframework.cloud.openfeign;
|
||||
import feign.Client;
|
||||
import feign.hc5.ApacheHttp5Client;
|
||||
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
|
||||
import org.apache.hc.client5.http.impl.classic.HttpClientBuilder;
|
||||
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager;
|
||||
import org.apache.hc.client5.http.io.HttpClientConnectionManager;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.boot.WebApplicationType;
|
||||
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||
import org.springframework.cloud.openfeign.clientconfig.HttpClient5FeignConfiguration.HttpClientBuilderCustomizer;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
/**
|
||||
* @author Nguyen Ky Thanh
|
||||
* @author Olga Maciaszek-Sharma
|
||||
* @author Kwangyong Kim
|
||||
*/
|
||||
class FeignHttpClient5ConfigurationTests {
|
||||
|
||||
@@ -72,4 +80,28 @@ class FeignHttpClient5ConfigurationTests {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldInstantiateHttpClient5ByUsingHttpClientBuilderCustomizer() {
|
||||
ConfigurableApplicationContext context = new SpringApplicationBuilder()
|
||||
.web(WebApplicationType.NONE)
|
||||
.sources(FeignAutoConfiguration.class, Config.class)
|
||||
.run();
|
||||
|
||||
CloseableHttpClient httpClient = context.getBean(CloseableHttpClient.class);
|
||||
assertThat(httpClient).isNotNull();
|
||||
HttpClientBuilderCustomizer customizer = context.getBean(HttpClientBuilderCustomizer.class);
|
||||
verify(customizer).customize(any(HttpClientBuilder.class));
|
||||
|
||||
if (context != null) {
|
||||
context.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class Config {
|
||||
@Bean
|
||||
HttpClientBuilderCustomizer customizer() {
|
||||
return Mockito.mock(HttpClientBuilderCustomizer.class);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user