采用Apache的httpclient作为RestTemplate的连接池配置,同时增加重试功能。
依赖
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
</dependency>
httpclient配置
@Data
@ConfigurationProperties(prefix = "http-client.conn-pool")
public class HttpClientConfig {
private Integer maxTotal = 600;
private Integer defaultMaxPerRoute = 300;
private List<HttpHostConfiguration> maxPerRoutes;
private Integer connectionRequestTimeout = 1000;
private Integer connectTimeout = 10000;
private Integer socketTimeout = 30000;
@Data
static class HttpHostConfiguration {
private String scheme;
private String host;
private Integer port;
private Integer maxPerRoute;
}
}
添加日志拦截器
@Slf4j
public class LoggingClientHttpRequestInterceptor implements ClientHttpRequestInterceptor {
@Override
public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
traceRequest(request, body);
long start = System.currentTimeMillis();
ClientHttpResponse response = execution.execute(request, body);
log.info("LoggingClientHttpRequestInterceptor traceRequest {} total spend {} ms", request.getURI(), System.currentTimeMillis() - start);
traceResponse(response);
return response;
}
private void traceRequest(HttpRequest request, byte[] body) throws IOException {
log.info("LoggingClientHttpRequestInterceptor traceRequest. URI:{},Method:{},Request body:{},Headers:{}",
request.getURI(), request.getMethod(), new String(body, StandardCharsets.UTF_8), request.getHeaders());
}
private void traceResponse(ClientHttpResponse response) throws IOException {
StringBuilder inputStringBuilder = new StringBuilder();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(response.getBody(), StandardCharsets.UTF_8));
String line = bufferedReader.readLine();
while (line != null) {
inputStringBuilder.append(line);
inputStringBuilder.append('\n');
line = bufferedReader.readLine();
}
log.info("LoggingClientHttpRequestInterceptor traceResponse. Status code:{},Status text:{},Response body:{},Headers:{}",
response.getStatusCode(), response.getStatusText(), inputStringBuilder.toString(), response.getHeaders());
}
}
连接池配置
@Slf4j
@Configuration
@ConditionalOnClass(value = {RestTemplate.class, CloseableHttpClient.class})
@EnableConfigurationProperties(HttpClientConfig.class)
public class RestTemplateConfig {
@Bean
public RestTemplate restTemplate(ClientHttpRequestFactory httpRequestFactory) {
RestTemplate restTemplate = new RestTemplate(new BufferingClientHttpRequestFactory(httpRequestFactory));
restTemplate.getInterceptors().add(new LoggingClientHttpRequestInterceptor());
log.info("初始化restTemplate完成");
return restTemplate;
}
@Bean
public ClientHttpRequestFactory httpRequestFactory(HttpClient httpClient) {
return new HttpComponentsClientHttpRequestFactory(httpClient);
}
@Bean
public CloseableHttpClient httpClient(PoolingHttpClientConnectionManager poolingHttpClientConnectionManager, RequestConfig requestConfig) {
return HttpClientBuilder.create()
.setDefaultRequestConfig(requestConfig)
.setConnectionManager(poolingHttpClientConnectionManager)
.build();
}
@Bean
public PoolingHttpClientConnectionManager poolingHttpClientConnectionManager(HttpClientConfig httpClientConfig) {
PoolingHttpClientConnectionManager result = new PoolingHttpClientConnectionManager();
result.setMaxTotal(httpClientConfig.getMaxTotal());
result.setDefaultMaxPerRoute(httpClientConfig.getDefaultMaxPerRoute());
if (CollectionUtils.isNotEmpty(httpClientConfig.getMaxPerRoutes())) {
for (HttpClientConfig.HttpHostConfiguration httpHostConfig : httpClientConfig.getMaxPerRoutes()) {
HttpHost host = new HttpHost(httpHostConfig.getHost(), httpHostConfig.getPort(), httpHostConfig.getScheme());
result.setMaxPerRoute(new HttpRoute(host), httpHostConfig.getMaxPerRoute());
}
}
return result;
}
@Bean
public RequestConfig requestConfig(HttpClientConfig httpClientConfig) {
return RequestConfig.custom()
.setConnectionRequestTimeout(httpClientConfig.getConnectionRequestTimeout())
.setConnectTimeout(httpClientConfig.getConnectTimeout())
.setSocketTimeout(httpClientConfig.getSocketTimeout())
.build();
}
}
对post请求添加retry操作
@Service
@EnableRetry
public class RestTemplateService {
@Resource
private RestTemplate restTemplate;
@Retryable(value = {RestClientException.class, ResourceAccessException.class}, maxAttempts = 2,
backoff = @Backoff(delay = 500L))
public <T> T postForObject(String url, Object request, Class<T> responseType){
return restTemplate.postForObject(url, request, responseType);
}
public RestTemplate getRestTemplate(){
return this.restTemplate;
}
}