Merge pull request #222 from ryanjbaxter/http-client-factories
Implementation of factories to provide Apache HTTP Clients
This commit is contained in:
@@ -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`.
|
||||
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user