Remove additional Commons HttpClient dependencies. Fixes #788 (#789)

Co-authored-by: Ryan Baxter <524254+ryanjbaxter@users.noreply.github.com>
This commit is contained in:
Ryan Baxter
2022-11-15 16:49:01 -05:00
committed by GitHub
parent 1ec3c6522d
commit 83c0eff4be
10 changed files with 12 additions and 248 deletions

View File

@@ -233,7 +233,7 @@ public class FeignAutoConfiguration {
}
@Bean
public okhttp3.OkHttpClient client(okhttp3.OkHttpClient.Builder builder, ConnectionPool connectionPool,
public okhttp3.OkHttpClient okHttpClient(okhttp3.OkHttpClient.Builder builder, ConnectionPool connectionPool,
FeignHttpClientProperties httpClientProperties) {
boolean followRedirects = httpClientProperties.isFollowRedirects();
int connectTimeout = httpClientProperties.getConnectionTimeout();

View File

@@ -1,77 +0,0 @@
/*
* Copyright 2013-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.
* 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;
import java.time.Duration;
import java.util.concurrent.TimeUnit;
import jakarta.annotation.PreDestroy;
import okhttp3.ConnectionPool;
import okhttp3.OkHttpClient;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.cloud.commons.httpclient.OkHttpClientConnectionPoolFactory;
import org.springframework.cloud.commons.httpclient.OkHttpClientFactory;
import org.springframework.cloud.openfeign.support.FeignHttpClientProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* Defualt configuration for {@link OkHttpClient}.
*
* @author Ryan Baxter
* @author Marcin Grzejszczak
* @author Spencer Gibb
* @author Olga Maciaszek-Sharma
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnMissingBean(okhttp3.OkHttpClient.class)
public class OkHttpFeignConfiguration {
private okhttp3.OkHttpClient okHttpClient;
@Bean
@ConditionalOnMissingBean(ConnectionPool.class)
public ConnectionPool httpClientConnectionPool(FeignHttpClientProperties httpClientProperties,
OkHttpClientConnectionPoolFactory connectionPoolFactory) {
int maxTotalConnections = httpClientProperties.getMaxConnections();
long timeToLive = httpClientProperties.getTimeToLive();
TimeUnit ttlUnit = httpClientProperties.getTimeToLiveUnit();
return connectionPoolFactory.create(maxTotalConnections, timeToLive, ttlUnit);
}
@Bean
public okhttp3.OkHttpClient client(OkHttpClientFactory httpClientFactory, ConnectionPool connectionPool,
FeignHttpClientProperties httpClientProperties) {
boolean followRedirects = httpClientProperties.isFollowRedirects();
int connectTimeout = httpClientProperties.getConnectionTimeout();
Duration reaTimeout = httpClientProperties.getOkHttp().getReadTimeout();
this.okHttpClient = httpClientFactory.createBuilder(httpClientProperties.isDisableSslValidation())
.connectTimeout(connectTimeout, TimeUnit.MILLISECONDS).followRedirects(followRedirects)
.readTimeout(reaTimeout).connectionPool(connectionPool).build();
return this.okHttpClient;
}
@PreDestroy
public void destroy() {
if (this.okHttpClient != null) {
this.okHttpClient.dispatcher().executorService().shutdown();
this.okHttpClient.connectionPool().evictAll();
}
}
}

View File

@@ -30,11 +30,9 @@ import org.springframework.cloud.client.loadbalancer.LoadBalancedRetryFactory;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClientsProperties;
import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory;
import org.springframework.cloud.openfeign.clientconfig.OkHttpFeignConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
/**
* Configuration instantiating a {@link LoadBalancerClient}-based {@link Client} object
@@ -48,7 +46,6 @@ import org.springframework.context.annotation.Import;
@ConditionalOnClass(OkHttpClient.class)
@ConditionalOnProperty("spring.cloud.openfeign.okhttp.enabled")
@ConditionalOnBean({ LoadBalancerClient.class, LoadBalancerClientFactory.class })
@Import(OkHttpFeignConfiguration.class)
@EnableConfigurationProperties(LoadBalancerClientsProperties.class)
class OkHttpFeignLoadBalancerConfiguration {

View File

@@ -26,7 +26,6 @@ import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.boot.WebApplicationType;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.cloud.commons.httpclient.HttpClientConfiguration;
import org.springframework.context.ConfigurableApplicationContext;
import static org.assertj.core.api.Assertions.assertThat;
@@ -50,7 +49,7 @@ class FeignHttpClient5ConfigurationTests {
@Test
void shouldInstantiateHttpClient5ByDefaultWhenDependenciesPresent() {
ConfigurableApplicationContext context = new SpringApplicationBuilder().web(WebApplicationType.NONE)
.sources(HttpClientConfiguration.class, FeignAutoConfiguration.class).run();
.sources(FeignAutoConfiguration.class).run();
verifyHc5BeansAvailable(context);
@@ -63,7 +62,7 @@ class FeignHttpClient5ConfigurationTests {
void shouldNotInstantiateHttpClient5ByWhenDependenciesPresentButPropertyDisabled() {
ConfigurableApplicationContext context = new SpringApplicationBuilder()
.properties("spring.cloud.openfeign.httpclient.hc5.enabled=false").web(WebApplicationType.NONE)
.sources(HttpClientConfiguration.class, FeignAutoConfiguration.class).run();
.sources(FeignAutoConfiguration.class).run();
assertThatExceptionOfType(NoSuchBeanDefinitionException.class)
.isThrownBy(() -> context.getBean(CloseableHttpClient.class));

View File

@@ -1,103 +0,0 @@
/*
* Copyright 2013-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.
* 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;
import java.lang.reflect.Field;
import javax.net.ssl.SSLContextSpi;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.X509TrustManager;
import org.apache.http.config.Lookup;
import org.apache.http.conn.HttpClientConnectionManager;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.impl.conn.DefaultHttpClientConnectionOperator;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.springframework.boot.WebApplicationType;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.cloud.commons.httpclient.HttpClientConfiguration;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.util.ReflectionUtils;
import static org.assertj.core.api.Assertions.assertThat;
/**
* @author Ryan Baxter
*/
// TODO: Bring back when there's corresponding HttpClient 5 support in Commons
@Disabled
class FeignHttpClientConfigurationTests {
private ConfigurableApplicationContext context;
@BeforeEach
void setUp() {
this.context = new SpringApplicationBuilder()
.properties("debug=true", "spring.cloud.openfeign.httpclient.disableSslValidation=true")
.web(WebApplicationType.NONE).sources(HttpClientConfiguration.class, FeignAutoConfiguration.class)
.run();
}
@AfterEach
void tearDown() {
if (this.context != null) {
this.context.close();
}
}
@Test
void disableSslTest() {
try {
HttpClientConnectionManager connectionManager = this.context.getBean(HttpClientConnectionManager.class);
Lookup<ConnectionSocketFactory> socketFactoryRegistry = getConnectionSocketFactoryLookup(connectionManager);
assertThat(socketFactoryRegistry.lookup("https")).isNotNull();
assertThat(this.getX509TrustManager(socketFactoryRegistry).getAcceptedIssuers()).isNull();
}
catch (RuntimeException e) {
// FIXME: java 16 need junit 5 compatible modified classpath extension
if (e.getMessage() == null || !e.getMessage().startsWith("Unable to make field private final")) {
ReflectionUtils.rethrowRuntimeException(e);
}
}
}
@SuppressWarnings("unchecked")
private Lookup<ConnectionSocketFactory> getConnectionSocketFactoryLookup(
HttpClientConnectionManager connectionManager) {
DefaultHttpClientConnectionOperator connectionOperator = (DefaultHttpClientConnectionOperator) this
.getField(connectionManager, "connectionOperator");
return (Lookup) this.getField(connectionOperator, "socketFactoryRegistry");
}
private X509TrustManager getX509TrustManager(Lookup<ConnectionSocketFactory> socketFactoryRegistry) {
ConnectionSocketFactory connectionSocketFactory = socketFactoryRegistry.lookup("https");
SSLSocketFactory sslSocketFactory = (SSLSocketFactory) this.getField(connectionSocketFactory, "socketfactory");
SSLContextSpi sslContext = (SSLContextSpi) this.getField(sslSocketFactory, "context");
return (X509TrustManager) this.getField(sslContext, "trustManager");
}
protected <T> Object getField(Object target, String name) {
Field field = ReflectionUtils.findField(target.getClass(), name);
ReflectionUtils.makeAccessible(field);
return ReflectionUtils.getField(field, target);
}
}

View File

@@ -27,7 +27,6 @@ import org.junit.jupiter.api.Test;
import org.springframework.boot.WebApplicationType;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.cloud.commons.httpclient.HttpClientConfiguration;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.util.ReflectionUtils;
@@ -47,8 +46,7 @@ class FeignOkHttpConfigurationTests {
"spring.cloud.openfeign.okhttp.enabled=true",
"spring.cloud.openfeign.httpclient.hc5.enabled=false",
"spring.cloud.openfeign.httpclient.okhttp.read-timeout=9s")
.web(WebApplicationType.NONE).sources(HttpClientConfiguration.class, FeignAutoConfiguration.class)
.run();
.web(WebApplicationType.NONE).sources(FeignAutoConfiguration.class).run();
}
@AfterEach

View File

@@ -19,7 +19,6 @@ package org.springframework.cloud.openfeign.invalid;
import org.junit.jupiter.api.Test;
import org.springframework.cloud.client.loadbalancer.LoadBalancerAutoConfiguration;
import org.springframework.cloud.commons.httpclient.HttpClientConfiguration;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.cloud.openfeign.FeignAutoConfiguration;
import org.springframework.cloud.openfeign.FeignClient;
@@ -64,7 +63,7 @@ class FeignClientValidationTests {
}
@Configuration(proxyBeanMethods = false)
@Import({ FeignAutoConfiguration.class, HttpClientConfiguration.class })
@Import({ FeignAutoConfiguration.class })
@EnableFeignClients(clients = NameAndServiceIdConfiguration.Client.class)
protected static class NameAndServiceIdConfiguration {
@@ -79,7 +78,7 @@ class FeignClientValidationTests {
}
@Configuration(proxyBeanMethods = false)
@Import({ FeignAutoConfiguration.class, HttpClientConfiguration.class })
@Import({ FeignAutoConfiguration.class })
@EnableFeignClients(clients = { DuplicatedFeignClientNamesConfiguration.FooClient.class,
DuplicatedFeignClientNamesConfiguration.BarClient.class })
protected static class DuplicatedFeignClientNamesConfiguration {

View File

@@ -25,10 +25,10 @@ import org.junit.jupiter.api.Test;
import org.springframework.boot.WebApplicationType;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.cloud.commons.httpclient.HttpClientConfiguration;
import org.springframework.cloud.loadbalancer.blocking.client.BlockingLoadBalancerClient;
import org.springframework.cloud.loadbalancer.config.BlockingLoadBalancerClientAutoConfiguration;
import org.springframework.cloud.loadbalancer.config.LoadBalancerAutoConfiguration;
import org.springframework.cloud.openfeign.FeignAutoConfiguration;
import org.springframework.context.ConfigurableApplicationContext;
import static org.assertj.core.api.Assertions.assertThat;
@@ -97,8 +97,8 @@ class FeignLoadBalancerAutoConfigurationTests {
private ConfigurableApplicationContext initContext(String... properties) {
return new SpringApplicationBuilder().web(WebApplicationType.NONE).properties(properties)
.sources(HttpClientConfiguration.class, LoadBalancerAutoConfiguration.class,
BlockingLoadBalancerClientAutoConfiguration.class, FeignLoadBalancerAutoConfiguration.class)
.sources(LoadBalancerAutoConfiguration.class, BlockingLoadBalancerClientAutoConfiguration.class,
FeignLoadBalancerAutoConfiguration.class, FeignAutoConfiguration.class)
.run();
}

View File

@@ -16,10 +16,7 @@
package org.springframework.cloud.openfeign.test;
import java.util.concurrent.TimeUnit;
import feign.Client;
import okhttp3.ConnectionPool;
import okhttp3.OkHttpClient;
import org.junit.jupiter.api.Test;
import org.mockito.MockingDetails;
@@ -28,10 +25,6 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.cloud.commons.httpclient.DefaultOkHttpClientConnectionPoolFactory;
import org.springframework.cloud.commons.httpclient.DefaultOkHttpClientFactory;
import org.springframework.cloud.commons.httpclient.OkHttpClientConnectionPoolFactory;
import org.springframework.cloud.commons.httpclient.OkHttpClientFactory;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.cloud.openfeign.loadbalancer.FeignBlockingLoadBalancerClient;
import org.springframework.context.annotation.Bean;
@@ -52,23 +45,9 @@ import static org.mockito.Mockito.mockingDetails;
@DirtiesContext
class OkHttpClientConfigurationTests {
@Autowired
OkHttpClientFactory okHttpClientFactory;
@Autowired
OkHttpClientConnectionPoolFactory connectionPoolFactory;
@Autowired
FeignBlockingLoadBalancerClient feignClient;
@Test
void testFactories() {
assertThat(connectionPoolFactory).isInstanceOf(OkHttpClientConnectionPoolFactory.class);
assertThat(connectionPoolFactory).isInstanceOf(TestConfig.MyOkHttpClientConnectionPoolFactory.class);
assertThat(okHttpClientFactory).isInstanceOf(OkHttpClientFactory.class);
assertThat(okHttpClientFactory).isInstanceOf(TestConfig.MyOkHttpClientFactory.class);
}
@Test
void testHttpClientWithFeign() {
Client delegate = feignClient.getDelegate();
@@ -94,38 +73,11 @@ class OkHttpClientConfigurationTests {
@EnableAutoConfiguration
static class TestConfig {
@Bean
public OkHttpClientConnectionPoolFactory connectionPoolFactory() {
return new MyOkHttpClientConnectionPoolFactory();
}
@Bean
public OkHttpClientFactory clientFactory(OkHttpClient.Builder builder) {
return new MyOkHttpClientFactory(builder);
}
@Bean
public OkHttpClient client() {
return mock(OkHttpClient.class);
}
static class MyOkHttpClientConnectionPoolFactory extends DefaultOkHttpClientConnectionPoolFactory {
@Override
public ConnectionPool create(int maxIdleConnections, long keepAliveDuration, TimeUnit timeUnit) {
return new ConnectionPool();
}
}
static class MyOkHttpClientFactory extends DefaultOkHttpClientFactory {
MyOkHttpClientFactory(OkHttpClient.Builder builder) {
super(builder);
}
}
}
}

View File

@@ -19,7 +19,6 @@ package org.springframework.cloud.openfeign.valid;
import org.junit.jupiter.api.Test;
import org.springframework.cloud.client.loadbalancer.LoadBalancerAutoConfiguration;
import org.springframework.cloud.commons.httpclient.HttpClientConfiguration;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.cloud.openfeign.FeignAutoConfiguration;
import org.springframework.cloud.openfeign.FeignClient;
@@ -62,7 +61,7 @@ class FeignClientValidationTests {
}
@Configuration(proxyBeanMethods = false)
@Import({ FeignAutoConfiguration.class, HttpClientConfiguration.class })
@Import({ FeignAutoConfiguration.class })
@EnableFeignClients(clients = GoodUrlConfiguration.Client.class)
protected static class GoodUrlConfiguration {
@@ -78,7 +77,7 @@ class FeignClientValidationTests {
}
@Configuration(proxyBeanMethods = false)
@Import({ FeignAutoConfiguration.class, HttpClientConfiguration.class })
@Import({ FeignAutoConfiguration.class })
@EnableFeignClients(clients = PlaceholderUrlConfiguration.Client.class)
protected static class PlaceholderUrlConfiguration {
@@ -94,7 +93,7 @@ class FeignClientValidationTests {
}
@Configuration(proxyBeanMethods = false)
@Import({ FeignAutoConfiguration.class, HttpClientConfiguration.class })
@Import({ FeignAutoConfiguration.class })
@EnableFeignClients(clients = GoodServiceIdConfiguration.Client.class)
protected static class GoodServiceIdConfiguration {