Created
November 30, 2015 19:38
-
-
Save mikeapr4/c40e32b4324e251d1ccc to your computer and use it in GitHub Desktop.
Java Spring Configuration to provide the Apache HttpClient as per recommendations from http://www.baeldung.com/httpclient-connection-management
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import org.apache.http.HeaderElement; | |
import org.apache.http.HeaderElementIterator; | |
import org.apache.http.HttpResponse; | |
import org.apache.http.client.config.RequestConfig; | |
import org.apache.http.config.Registry; | |
import org.apache.http.config.RegistryBuilder; | |
import org.apache.http.conn.ConnectionKeepAliveStrategy; | |
import org.apache.http.conn.socket.ConnectionSocketFactory; | |
import org.apache.http.conn.socket.PlainConnectionSocketFactory; | |
import org.apache.http.conn.ssl.SSLConnectionSocketFactory; | |
import org.apache.http.conn.ssl.SSLContextBuilder; | |
import org.apache.http.conn.ssl.TrustSelfSignedStrategy; | |
import org.apache.http.impl.client.CloseableHttpClient; | |
import org.apache.http.impl.client.HttpClients; | |
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; | |
import org.apache.http.message.BasicHeaderElementIterator; | |
import org.apache.http.protocol.HTTP; | |
import org.apache.http.protocol.HttpContext; | |
import org.slf4j.Logger; | |
import org.slf4j.LoggerFactory; | |
import org.springframework.context.annotation.Bean; | |
import org.springframework.context.annotation.Configuration; | |
import org.springframework.scheduling.annotation.EnableScheduling; | |
import org.springframework.scheduling.annotation.Scheduled; | |
import java.security.KeyManagementException; | |
import java.security.KeyStoreException; | |
import java.security.NoSuchAlgorithmException; | |
import java.util.concurrent.TimeUnit; | |
/** | |
* Spring Configuration for HTTP Clients. | |
* <p/> | |
* - Supports both HTTP and HTTPS | |
* - Uses a connection pool to re-use connections and save overhead of creating connections. | |
* - Has a custom connection keep-alive strategy (to apply a default keep-alive if one isn't specified) | |
* - Starts an idle connection monitor to continuously clean up stale connections. | |
* <p/> | |
* Tested with: | |
* - org.apache.httpcomponents:httpclient:4.3.5 | |
* - org.springframework:spring-context:4.1.6.RELEASE | |
* see http://www.baeldung.com/httpclient-connection-management | |
*/ | |
@Configuration | |
@EnableScheduling | |
public class HttpClientConfiguration { | |
private static final Logger LOGGER = LoggerFactory.getLogger(HttpClientConfiguration.class); | |
// Determines the timeout in milliseconds until a connection is established. | |
private static final int CONNECT_TIMEOUT = 30000; | |
// Returns the timeout in milliseconds used when requesting a connection from the connection manager. | |
private static final int REQUEST_TIMEOUT = 30000; | |
// Defines the socket timeout (SO_TIMEOUT) in milliseconds, which is the timeout for waiting for data or, | |
// put differently, a maximum period inactivity between two consecutive data packets). | |
private static final int SOCKET_TIMEOUT = 60000; | |
private static final int MAX_TOTAL_CONNECTIONS = 20; | |
private static final int ONE_SECOND_IN_MILLIS = 1000; | |
private static final int DEFAULT_KEEP_ALIVE_TIME_MILLIS = 5 * ONE_SECOND_IN_MILLIS; | |
private static final int CLOSE_IDLE_CONNECTION_WAIT_TIME_SECS = 30; | |
@Bean | |
public PoolingHttpClientConnectionManager getPoolingConnectionManager() { | |
SSLContextBuilder builder = new SSLContextBuilder(); | |
try { | |
builder.loadTrustMaterial(null, new TrustSelfSignedStrategy()); | |
} catch (NoSuchAlgorithmException | KeyStoreException e) { | |
LOGGER.error("Pooling Connection Manager Initialisation failure because of " + e.getMessage(), e); | |
} | |
SSLConnectionSocketFactory sslsf = null; | |
try { | |
sslsf = new SSLConnectionSocketFactory(builder.build()); | |
} catch (KeyManagementException | NoSuchAlgorithmException e) { | |
LOGGER.error("Pooling Connection Manager Initialisation failure because of " + e.getMessage(), e); | |
} | |
Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder | |
.<ConnectionSocketFactory>create().register("https", sslsf) | |
.register("http", new PlainConnectionSocketFactory()) | |
.build(); | |
PoolingHttpClientConnectionManager poolingConnectionManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry); | |
poolingConnectionManager.setMaxTotal(MAX_TOTAL_CONNECTIONS); | |
return poolingConnectionManager; | |
} | |
@Bean | |
public Runnable getIdleConnectionMonitor(final PoolingHttpClientConnectionManager connectionManager) { | |
return new Runnable() { | |
@Override | |
@Scheduled(fixedDelay = 10000) | |
public void run() { | |
try { | |
if (connectionManager != null) { | |
LOGGER.trace("run IdleConnectionMonitor - Closing expired and idle connections..."); | |
connectionManager.closeExpiredConnections(); | |
connectionManager.closeIdleConnections(CLOSE_IDLE_CONNECTION_WAIT_TIME_SECS, TimeUnit.SECONDS); | |
} else { | |
LOGGER.trace("run IdleConnectionMonitor - Http Client Connection manager is not initialised"); | |
} | |
} catch (Exception e) { | |
LOGGER.error("run IdleConnectionMonitor - Exception occurred. msg={}, e={}", e.getMessage(), e); | |
} | |
} | |
}; | |
} | |
@Bean | |
public ConnectionKeepAliveStrategy getConnectionKeepAliveStrategy() { | |
return new ConnectionKeepAliveStrategy() { | |
@Override | |
public long getKeepAliveDuration(HttpResponse response, HttpContext context) { | |
HeaderElementIterator it = new BasicHeaderElementIterator | |
(response.headerIterator(HTTP.CONN_KEEP_ALIVE)); | |
while (it.hasNext()) { | |
HeaderElement he = it.nextElement(); | |
String param = he.getName(); | |
String value = he.getValue(); | |
if (value != null && param.equalsIgnoreCase("timeout")) { | |
return Long.parseLong(value) * ONE_SECOND_IN_MILLIS; | |
} | |
} | |
return DEFAULT_KEEP_ALIVE_TIME_MILLIS; | |
} | |
}; | |
} | |
@Bean | |
public CloseableHttpClient getHttpClient() { | |
RequestConfig requestConfig = RequestConfig.custom() | |
.setConnectionRequestTimeout(REQUEST_TIMEOUT) | |
.setConnectTimeout(CONNECT_TIMEOUT) | |
.setSocketTimeout(SOCKET_TIMEOUT).build(); | |
return HttpClients.custom() | |
.setDefaultRequestConfig(requestConfig) | |
.setConnectionManager(getPoolingConnectionManager()) | |
.setKeepAliveStrategy(getConnectionKeepAliveStrategy()) | |
.build(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment