Merge pull request #222 from ryanjbaxter/http-client-factories

Implementation of factories to provide Apache HTTP Clients
This commit is contained in:
Ryan Baxter
2017-08-03 11:08:32 -04:00
committed by GitHub
18 changed files with 802 additions and 1 deletions

View File

@@ -487,3 +487,16 @@ spring:
inetutils:
useOnlySiteLocalInterfaces: true
----
[[http-clients]]
=== HTTP Client Factories
Spring Cloud Commons provides beans for creating both Apache HTTP clients (`ApacheHttpClientFactory`)
as well as OK HTTP clients (`OkHttpClientFactory`). The `OkHttpClientFactory` bean will only be created
if the OK HTTP jar is on the classpath. In addition, Spring Cloud Commons provides beans for creating
the connection managers used by both clients, `ApacheHttpClientConnectionManagerFactory` for the Apache
HTTP client and `OkHttpClientConnectionPoolFactory` for the OK HTTP client. You can provide
your own implementation of these beans if you would like to customize how the HTTP clients are created
in downstream projects. You can also disable the creation of these beans by setting
`spring.cloud.httpclientfactories.apache.enabled` or `spring.cloud.httpclientfactories.ok.enabled` to
`false`.

View File

@@ -35,6 +35,11 @@
</plugin>
</plugins>
</build>
<properties>
<okhttp3.version>3.6.0</okhttp3.version>
<apachehttpclient.version>4.5.1</apachehttpclient.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
@@ -96,6 +101,23 @@
<artifactId>json-path</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>${okhttp3.version}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>logging-interceptor</artifactId>
<version>${okhttp3.version}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>${apachehttpclient.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>

View File

@@ -0,0 +1,47 @@
/*
*
* * Copyright 2013-2016 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
* *
* * http://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.commons.httpclient;
import java.util.concurrent.TimeUnit;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.HttpClientConnectionManager;
/**
* Interface for creating an {@link HttpClientConnectionManager}.
* @author Ryan Baxter
*/
public interface ApacheHttpClientConnectionManagerFactory {
public static final String HTTP_SCHEME = "http";
public static final String HTTPS_SCHEME = "https";
/**
* Creates a new {@link HttpClientConnectionManager}.
* @param disableSslValidation True to disable SSL validation, false otherwise
* @param maxTotalConnections The total number of connections
* @param maxConnectionsPerRoute The total number of connections per route
* @param timeToLive The time a connection is allowed to exist
* @param timeUnit The time unit for the time to live value
* @param registryBuilder The {@link RegistryBuilder} to use in the connection manager
* @return A new {@link HttpClientConnectionManager}
*/
public HttpClientConnectionManager newConnectionManager(boolean disableSslValidation,
int maxTotalConnections, int maxConnectionsPerRoute, long timeToLive,
TimeUnit timeUnit, RegistryBuilder registryBuilder);
}

View File

@@ -0,0 +1,37 @@
/*
*
* * Copyright 2013-2016 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
* *
* * http://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.commons.httpclient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.conn.HttpClientConnectionManager;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
/**
* Factory for creating a new {@link CloseableHttpClient}.
* @author Ryan Baxter
*/
public interface ApacheHttpClientFactory {
/**
* Creates an {@link HttpClientBuilder} that can be used to create a new {@link CloseableHttpClient}.
* @return A {@link HttpClientBuilder}
*/
public HttpClientBuilder createBuilder();
}

View File

@@ -0,0 +1,85 @@
package org.springframework.cloud.commons.httpclient;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.concurrent.TimeUnit;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import org.apache.commons.logging.LogFactory;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.HttpClientConnectionManager;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.commons.logging.Log;
/**
* Default implementation of {@link ApacheHttpClientConnectionManagerFactory}.
* @author Ryan Baxter
*/
public class DefaultApacheHttpClientConnectionManagerFactory
implements ApacheHttpClientConnectionManagerFactory {
private static final Log LOG = LogFactory
.getLog(DefaultApacheHttpClientConnectionManagerFactory.class);
public HttpClientConnectionManager newConnectionManager(boolean disableSslValidation,
int maxTotalConnections, int maxConnectionsPerRoute) {
return newConnectionManager(disableSslValidation, maxTotalConnections,
maxConnectionsPerRoute, -1, TimeUnit.MILLISECONDS, null);
}
@Override
public HttpClientConnectionManager newConnectionManager(boolean disableSslValidation,
int maxTotalConnections, int maxConnectionsPerRoute, long timeToLive,
TimeUnit timeUnit, RegistryBuilder registryBuilder) {
if (registryBuilder == null) {
registryBuilder = RegistryBuilder.<ConnectionSocketFactory> create()
.register(HTTP_SCHEME, PlainConnectionSocketFactory.INSTANCE);
}
if (disableSslValidation) {
try {
final SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, new TrustManager[] { new X509TrustManager() {
@Override
public void checkClientTrusted(X509Certificate[] x509Certificates,
String s) throws CertificateException {
}
@Override
public void checkServerTrusted(X509Certificate[] x509Certificates,
String s) throws CertificateException {
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return null;
}
} }, new SecureRandom());
registryBuilder.register(HTTPS_SCHEME, new SSLConnectionSocketFactory(
sslContext, NoopHostnameVerifier.INSTANCE));
}
catch (NoSuchAlgorithmException e) {
LOG.warn("Error creating SSLContext", e);
}
catch (KeyManagementException e) {
LOG.warn("Error creating SSLContext", e);
}
}
final Registry<ConnectionSocketFactory> registry = registryBuilder.build();
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(
registry, null, null, null, timeToLive, timeUnit);
connectionManager.setMaxTotal(maxTotalConnections);
connectionManager.setDefaultMaxPerRoute(maxConnectionsPerRoute);
return connectionManager;
}
}

View File

@@ -0,0 +1,23 @@
package org.springframework.cloud.commons.httpclient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.conn.HttpClientConnectionManager;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
/**
* Default implementation of {@link ApacheHttpClientFactory}.
* @author Ryan Baxter
*/
public class DefaultApacheHttpClientFactory implements ApacheHttpClientFactory {
/**
* A default {@link HttpClientBuilder}. The {@link HttpClientBuilder} returned will
* have content compression disabled, cookie management disabled, and use system properties.
*/
@Override
public HttpClientBuilder createBuilder() {
return HttpClientBuilder.create().disableContentCompression()
.disableCookieManagement().useSystemProperties();
}
}

View File

@@ -0,0 +1,17 @@
package org.springframework.cloud.commons.httpclient;
import okhttp3.ConnectionPool;
import java.util.concurrent.TimeUnit;
/**
* Default implementation of {@link OkHttpClientConnectionPoolFactory}.
* @author Ryan Baxter
*/
public class DefaultOkHttpClientConnectionPoolFactory implements OkHttpClientConnectionPoolFactory {
@Override
public ConnectionPool create(int maxIdleConnections, long keepAliveDuration, TimeUnit timeUnit) {
return new ConnectionPool(maxIdleConnections, keepAliveDuration, timeUnit);
}
}

View File

@@ -0,0 +1,47 @@
package org.springframework.cloud.commons.httpclient;
import okhttp3.ConnectionPool;
import okhttp3.OkHttpClient;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.util.concurrent.TimeUnit;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Default implementation of {@link OkHttpClientFactory}.
* @author Ryan Baxter
*/
public class DefaultOkHttpClientFactory implements OkHttpClientFactory {
private static final Log LOG = LogFactory.getLog(DefaultOkHttpClientFactory.class);
@Override
public OkHttpClient.Builder createBuilder(boolean disableSslValidation) {
OkHttpClient.Builder builder = new OkHttpClient.Builder();
if (disableSslValidation) {
try {
X509TrustManager disabledTrustManager = new DisableValidationTrustManager();
TrustManager[] trustManagers = new TrustManager[1];
trustManagers[0] = disabledTrustManager;
SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, trustManagers, new java.security.SecureRandom());
SSLSocketFactory disabledSSLSocketFactory = sslContext.getSocketFactory();
builder.sslSocketFactory(disabledSSLSocketFactory, disabledTrustManager);
builder.hostnameVerifier(new TrustAllHostnames());
}
catch (NoSuchAlgorithmException e) {
LOG.warn("Error setting SSLSocketFactory in OKHttpClient", e);
}
catch (KeyManagementException e) {
LOG.warn("Error setting SSLSocketFactory in OKHttpClient", e);
}
}
return builder;
}
}

View File

@@ -0,0 +1,51 @@
package org.springframework.cloud.commons.httpclient;
import okhttp3.OkHttpClient;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @author Ryan Baxter
*/
@Configuration
public class HttpClientConfiguration {
@Configuration
@ConditionalOnProperty(name = "spring.cloud.httpclientfactories.apache.enabled", matchIfMissing = true)
static class ApacheHttpClientConfiguration {
@Bean
@ConditionalOnMissingBean
public ApacheHttpClientConnectionManagerFactory connManFactory() {
return new DefaultApacheHttpClientConnectionManagerFactory();
}
@Bean
@ConditionalOnMissingBean
public ApacheHttpClientFactory apacheHttpClientFactory() {
return new DefaultApacheHttpClientFactory();
}
}
@Configuration
@ConditionalOnProperty(name = "spring.cloud.httpclientfactories.ok.enabled", matchIfMissing = true)
@ConditionalOnClass(OkHttpClient.class)
static class OkHttpClientConfiguration {
@Bean
@ConditionalOnMissingBean
public OkHttpClientConnectionPoolFactory connPoolFactory() {
return new DefaultOkHttpClientConnectionPoolFactory();
}
@Bean
@ConditionalOnMissingBean
public OkHttpClientFactory okHttpClientFactory() {
return new DefaultOkHttpClientFactory();
}
}
}

View File

@@ -0,0 +1,21 @@
package org.springframework.cloud.commons.httpclient;
import okhttp3.ConnectionPool;
import java.util.concurrent.TimeUnit;
/**
* Creates {@link ConnectionPool}s for {@link okhttp3.OkHttpClient}s
* @author Ryan Baxter
*/
public interface OkHttpClientConnectionPoolFactory {
/**
* Creates a new {@link ConnectionPool}.
* @param maxIdleConnections number of max idle connections to allow
* @param keepAliveDuration amount of time to keep connections alive
* @param timeUnit the time unit for the keep alive duration
* @return A new {@link ConnectionPool}
*/
public ConnectionPool create(int maxIdleConnections, long keepAliveDuration, TimeUnit timeUnit);
}

View File

@@ -0,0 +1,54 @@
package org.springframework.cloud.commons.httpclient;
import okhttp3.ConnectionPool;
import okhttp3.OkHttpClient;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.concurrent.TimeUnit;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.X509TrustManager;
/**
* Creates new {@link OkHttpClient}s.
* @author Ryan Baxter
*/
public interface OkHttpClientFactory {
/**
* Creates a {@link OkHttpClient.Builder} used to build an {@link OkHttpClient}.
* @param disableSslValidation Disables SSL validation
* @return A new {@link OkHttpClient.Builder}
*/
public OkHttpClient.Builder createBuilder(boolean disableSslValidation);
/**
* A {@link X509TrustManager} that does not validate SSL certificates.
*/
public static class DisableValidationTrustManager implements X509TrustManager {
@Override
public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {}
@Override
public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {}
@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
}
/**
* A {@link HostnameVerifier} that does not validate any hostnames.
*/
public static class TrustAllHostnames implements HostnameVerifier {
@Override
public boolean verify(String s, SSLSession sslSession) {
return true;
}
}
}

View File

@@ -8,7 +8,8 @@ org.springframework.cloud.client.loadbalancer.LoadBalancerAutoConfiguration,\
org.springframework.cloud.client.serviceregistry.ServiceRegistryAutoConfiguration,\
org.springframework.cloud.commons.util.UtilAutoConfiguration,\
org.springframework.cloud.client.discovery.composite.CompositeDiscoveryClientAutoConfiguration,\
org.springframework.cloud.client.discovery.simple.SimpleDiscoveryClientAutoConfiguration
org.springframework.cloud.client.discovery.simple.SimpleDiscoveryClientAutoConfiguration,\
org.springframework.cloud.commons.httpclient.HttpClientConfiguration
# Environment Post Processors

View File

@@ -0,0 +1,142 @@
package org.springframework.cloud.commons.httpclient;
import okhttp3.ConnectionPool;
import okhttp3.OkHttpClient;
import java.util.concurrent.TimeUnit;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.X509TrustManager;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.HttpClientConnectionManager;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.context.junit4.SpringRunner;
import static org.junit.Assert.assertTrue;
/**
* @author Ryan Baxter
*/
@RunWith(SpringRunner.class)
@SpringBootTest(classes = CustomApplication.class, properties = {"spring.cloud.httpclient.ok.enabled: true"})
public class CustomHttpClientConfigurationTests {
@Autowired
ApacheHttpClientFactory httpClientFactory;
@Autowired
ApacheHttpClientConnectionManagerFactory connectionManagerFactory;
@Autowired
OkHttpClientFactory okHttpClientFactory;
@Autowired
OkHttpClientConnectionPoolFactory okHttpClientConnectionPoolFactory;
@Test
public void connManFactory() throws Exception {
assertTrue(ApacheHttpClientConnectionManagerFactory.class
.isInstance(connectionManagerFactory));
assertTrue(CustomApplication.MyApacheHttpClientConnectionManagerFactory.class
.isInstance(connectionManagerFactory));
}
@Test
public void apacheHttpClientFactory() throws Exception {
assertTrue(ApacheHttpClientFactory.class.isInstance(httpClientFactory));
assertTrue(CustomApplication.MyApacheHttpClientFactory.class
.isInstance(httpClientFactory));
}
@Test
public void connectionPoolFactory() throws Exception {
assertTrue(OkHttpClientConnectionPoolFactory.class.isInstance(okHttpClientConnectionPoolFactory));
assertTrue(CustomApplication.MyOkHttpConnectionPoolFactory.class.isInstance(okHttpClientConnectionPoolFactory));
}
@Test
public void okHttpClientFactory() throws Exception {
assertTrue(OkHttpClientFactory.class.isInstance(okHttpClientFactory));
assertTrue(CustomApplication.MyOkHttpClientFactory.class.isInstance(okHttpClientFactory));
}
}
@Configuration
@EnableAutoConfiguration
class CustomApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
@Configuration
static class MyConfig {
@Bean
public ApacheHttpClientFactory clientFactory() {
return new MyApacheHttpClientFactory();
}
@Bean
public ApacheHttpClientConnectionManagerFactory connectionManagerFactory() {
return new MyApacheHttpClientConnectionManagerFactory();
}
@Bean
public OkHttpClientConnectionPoolFactory connectionPoolFactory() {
return new MyOkHttpConnectionPoolFactory();
}
@Bean
public OkHttpClientFactory okHttpClientFactory() {
return new MyOkHttpClientFactory();
}
}
static class MyApacheHttpClientFactory implements ApacheHttpClientFactory {
@Override
public HttpClientBuilder createBuilder() {
return HttpClientBuilder.create();
}
}
static class MyApacheHttpClientConnectionManagerFactory
implements ApacheHttpClientConnectionManagerFactory {
@Override
public HttpClientConnectionManager newConnectionManager(
boolean disableSslValidation, int maxTotalConnections,
int maxConnectionsPerRoute, long timeToLive, TimeUnit timeUnit,
RegistryBuilder registryBuilder) {
return null;
}
}
static class MyOkHttpClientFactory implements OkHttpClientFactory {
@Override
public OkHttpClient.Builder createBuilder(boolean disableSslValidation) {
return new OkHttpClient.Builder();
}
}
static class MyOkHttpConnectionPoolFactory implements OkHttpClientConnectionPoolFactory {
@Override
public ConnectionPool create(int maxIdleConnections, long keepAliveDuration, TimeUnit timeUnit) {
return null;
}
}
}

View File

@@ -0,0 +1,52 @@
package org.springframework.cloud.commons.httpclient;
import java.lang.reflect.Field;
import java.util.concurrent.TimeUnit;
import org.apache.http.conn.HttpClientConnectionManager;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.junit.Test;
import org.springframework.util.ReflectionUtils;
import static org.junit.Assert.*;
/**
* @author Ryan Baxter
*/
public class DefaultApacheHttpClientConnectionManagerFactoryTests {
@Test
public void newConnectionManager() throws Exception {
HttpClientConnectionManager connectionManager = new DefaultApacheHttpClientConnectionManagerFactory()
.newConnectionManager(false, 2, 6);
assertEquals(6, ((PoolingHttpClientConnectionManager) connectionManager)
.getDefaultMaxPerRoute());
assertEquals(2,
((PoolingHttpClientConnectionManager) connectionManager).getMaxTotal());
Object pool = getField(((PoolingHttpClientConnectionManager) connectionManager),
"pool");
assertEquals(-1l, getField(pool, "timeToLive"));
TimeUnit timeUnit = getField(pool, "tunit");
assertEquals(TimeUnit.MILLISECONDS, timeUnit);
}
@Test
public void newConnectionManagerWithTTL() throws Exception {
HttpClientConnectionManager connectionManager = new DefaultApacheHttpClientConnectionManagerFactory()
.newConnectionManager(false, 2, 6, 56l, TimeUnit.DAYS, null);
assertEquals(6, ((PoolingHttpClientConnectionManager) connectionManager)
.getDefaultMaxPerRoute());
assertEquals(2,
((PoolingHttpClientConnectionManager) connectionManager).getMaxTotal());
Object pool = getField(((PoolingHttpClientConnectionManager) connectionManager),
"pool");
assertEquals(56l, getField(pool, "timeToLive"));
TimeUnit timeUnit = getField(pool, "tunit");
assertEquals(TimeUnit.DAYS, timeUnit);
}
protected <T> T getField(Object target, String name) {
Field field = ReflectionUtils.findField(target.getClass(), name);
ReflectionUtils.makeAccessible(field);
Object value = ReflectionUtils.getField(field, target);
return (T) value;
}
}

View File

@@ -0,0 +1,42 @@
package org.springframework.cloud.commons.httpclient;
import java.lang.reflect.Field;
import org.apache.http.client.config.CookieSpecs;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.Configurable;
import org.apache.http.conn.HttpClientConnectionManager;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.assertj.core.api.Assertions;
import org.junit.Test;
import org.springframework.util.ReflectionUtils;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.mock;
/**
* @author Ryan Baxter
*/
public class DefaultApacheHttpClientFactoryTests {
@Test
public void createClient() throws Exception {
final RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(100)
.setConnectTimeout(200).setCookieSpec(CookieSpecs.IGNORE_COOKIES).build();
CloseableHttpClient httpClient = new DefaultApacheHttpClientFactory().createBuilder().
setConnectionManager(mock(HttpClientConnectionManager.class)).
setDefaultRequestConfig(requestConfig).build();
Assertions.assertThat(httpClient).isInstanceOf(Configurable.class);
RequestConfig config = ((Configurable) httpClient).getConfig();
assertEquals(100, config.getSocketTimeout());
assertEquals(200, config.getConnectTimeout());
assertEquals(CookieSpecs.IGNORE_COOKIES, config.getCookieSpec());
}
protected <T> T getField(Object target, String name) {
Field field = ReflectionUtils.findField(target.getClass(), name);
ReflectionUtils.makeAccessible(field);
Object value = ReflectionUtils.getField(field, target);
return (T) value;
}
}

View File

@@ -0,0 +1,66 @@
package org.springframework.cloud.commons.httpclient;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.context.junit4.SpringRunner;
import static org.junit.Assert.*;
/**
* @author Ryan Baxter
*/
@RunWith(SpringRunner.class)
@SpringBootTest(classes = MyApplication.class, properties = {"spring.cloud.httpclient.ok.enabled: true"})
public class DefaultHttpClientConfigurationTests {
@Autowired
ApacheHttpClientFactory httpClientFactory;
@Autowired
ApacheHttpClientConnectionManagerFactory connectionManagerFactory;
@Autowired
OkHttpClientFactory okHttpClientFactory;
@Autowired
OkHttpClientConnectionPoolFactory okHttpClientConnectionPoolFactory;
@Test
public void connManFactory() throws Exception {
assertTrue(ApacheHttpClientConnectionManagerFactory.class
.isInstance(connectionManagerFactory));
assertTrue(DefaultApacheHttpClientConnectionManagerFactory.class
.isInstance(connectionManagerFactory));
}
@Test
public void apacheHttpClientFactory() throws Exception {
assertTrue(ApacheHttpClientFactory.class.isInstance(httpClientFactory));
assertTrue(DefaultApacheHttpClientFactory.class.isInstance(httpClientFactory));
}
@Test
public void connPoolFactory() throws Exception {
assertTrue(OkHttpClientConnectionPoolFactory.class.isInstance(okHttpClientConnectionPoolFactory));
assertTrue(DefaultOkHttpClientConnectionPoolFactory.class.isInstance(okHttpClientConnectionPoolFactory));
}
@Test
public void setOkHttpClientFactory() throws Exception {
assertTrue(OkHttpClientFactory.class.isInstance(okHttpClientFactory));
assertTrue(DefaultOkHttpClientFactory.class.isInstance(okHttpClientFactory));
}
}
@Configuration
@EnableAutoConfiguration
class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}

View File

@@ -0,0 +1,34 @@
package org.springframework.cloud.commons.httpclient;
import okhttp3.ConnectionPool;
import java.lang.reflect.Field;
import java.util.concurrent.TimeUnit;
import org.junit.Test;
import org.springframework.util.ReflectionUtils;
import static org.junit.Assert.assertEquals;
/**
* @author Ryan Baxter
*/
public class DefaultOkHttpClientConnectionPoolFactoryTest {
@Test
public void create() throws Exception {
DefaultOkHttpClientConnectionPoolFactory connectionPoolFactory = new DefaultOkHttpClientConnectionPoolFactory();
ConnectionPool connectionPool = connectionPoolFactory.create(2,
3, TimeUnit.MILLISECONDS);
int idleConnections = getField(connectionPool, "maxIdleConnections");
long keepAliveDuration = getField(connectionPool, "keepAliveDurationNs");
assertEquals(2, idleConnections);
assertEquals(TimeUnit.MILLISECONDS.toNanos(3), keepAliveDuration);
}
protected <T> T getField(Object target, String name) {
Field field = ReflectionUtils.findField(target.getClass(), name);
ReflectionUtils.makeAccessible(field);
Object value = ReflectionUtils.getField(field, target);
return (T) value;
}
}

View File

@@ -0,0 +1,47 @@
package org.springframework.cloud.commons.httpclient;
import okhttp3.ConnectionPool;
import okhttp3.OkHttpClient;
import java.lang.reflect.Field;
import java.util.concurrent.TimeUnit;
import javax.net.ssl.HostnameVerifier;
import org.junit.Test;
import org.springframework.util.ReflectionUtils;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
/**
* @author Ryan Baxter
*/
public class DefaultOkHttpClientFactoryTest {
@Test
public void create() throws Exception {
DefaultOkHttpClientFactory okHttpClientFactory = new DefaultOkHttpClientFactory();
DefaultOkHttpClientConnectionPoolFactory poolFactory = new DefaultOkHttpClientConnectionPoolFactory();
ConnectionPool pool = poolFactory.create(4, 5, TimeUnit.DAYS);
OkHttpClient httpClient = okHttpClientFactory.createBuilder(true).
connectTimeout(2, TimeUnit.MILLISECONDS).
readTimeout(3, TimeUnit.HOURS).
followRedirects(true).
connectionPool(pool).build();
int connectTimeout = getField(httpClient, "connectTimeout");
assertEquals(2, connectTimeout);
int readTimeout = getField(httpClient, "readTimeout");
assertEquals(TimeUnit.HOURS.toMillis(3), readTimeout);
boolean followRedirects = getField(httpClient, "followRedirects");
assertTrue(followRedirects);
ConnectionPool poolFromClient = getField(httpClient, "connectionPool");
assertEquals(pool, poolFromClient);
HostnameVerifier hostnameVerifier = getField(httpClient, "hostnameVerifier");
assertTrue(OkHttpClientFactory.TrustAllHostnames.class.isInstance(hostnameVerifier));
}
protected <T> T getField(Object target, String name) {
Field field = ReflectionUtils.findField(target.getClass(), name);
ReflectionUtils.makeAccessible(field);
Object value = ReflectionUtils.getField(field, target);
return (T) value;
}
}