RestTemplate backed by Apache HttpClient Connection Pool. Addresses RestTemplate HttpConnection exhaustion. Note this implementation is not route tunable and should be expanded when tuning by route is required. Example error: I/O error on POST request for "https://someendpoint": Timeout waiting for connection from pool; nested exception is org.apache.http.conn.ConnectionPoolTimeoutException: Timeout waiting for connection from pool
import org.apache.http.client.config.RequestConfig;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class ClientHttpPoolConfiguration {
@Autowired
private HttpConnectionPoolConfiguration poolConfiguration;
@Bean
public PoolingHttpClientConnectionManager poolingHttpClientConnectionManager() {
PoolingHttpClientConnectionManager result = new PoolingHttpClientConnectionManager();
result.setDefaultMaxPerRoute(poolConfiguration.getMaxPerRoute());
result.setMaxTotal(poolConfiguration.getMaxTotal());
return result;
}
@Bean
public RequestConfig requestConfig() {
RequestConfig result = RequestConfig.custom()
.setConnectionRequestTimeout(poolConfiguration.getConnectionRequestTimeout())
.setConnectTimeout(poolConfiguration.getConnectTimeout())
.setSocketTimeout(poolConfiguration.getSocketTimeout())
.build();
return result;
}
@Bean
public CloseableHttpClient httpClient(PoolingHttpClientConnectionManager poolingHttpClientConnectionManager,
RequestConfig requestConfig) {
CloseableHttpClient result = HttpClientBuilder
.create()
.setConnectionManager(poolingHttpClientConnectionManager)
.setDefaultRequestConfig(requestConfig)
.build();
return result;
}
}
import org.apache.http.client.HttpClient;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;
@Configuration
public class RestTemplateConfiguration {
@Bean
public RestTemplate restTemplate(HttpClient httpClient) {
HttpComponentsClientHttpRequestFactory httpRequestFactory = new
HttpComponentsClientHttpRequestFactory();
httpRequestFactory.setHttpClient(httpClient);
RestTemplate restTemplate = new RestTemplate(httpRequestFactory);
restTemplate.setErrorHandler(new CustomErrorResponseHandler());
return restTemplate;
}
}
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Component
@ConfigurationProperties(prefix = "httppool")
@Data
public class HttpConnectionPoolConfiguration {
private Integer maxPerRoute;
private Integer maxTotal;
private Integer connectionRequestTimeout;
private Integer connectTimeout;
private Integer socketTimeout;
}
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.3</version>
</dependency>
httppool:
maxPerRoute: 100
maxTotal: 1000
connectionRequestTimeout: 300
connectTimeout: 300
socketTimeout: 1500