restTemplate实现ClientHttpRequestInterceptor,报错org.apache.http.conn.ConnectionPoolTimeoutException: Timeout waiting for connection from pool
代码如下:
@Configuration
public class HttpConfig {
private static final Integer RETRY_COUNT = 3;
@Bean
public RestTemplate restTemplate() {
//设置超时时间
HttpComponentsClientHttpRequestFactory httpRequestFactory = new HttpComponentsClientHttpRequestFactory();
httpRequestFactory.setConnectionRequestTimeout(10000);
/** 连接超时参数 ConnectTimeout,让用户配置建连阶段的最长等待时间 **/
httpRequestFactory.setConnectTimeout(10000);
/** 读取超时参数 ReadTimeout,用来控制从 Socket 上读取数据的最长等待时间 5s**/
httpRequestFactory.setReadTimeout(5000);
RestTemplate restTemplate = new RestTemplate(httpRequestFactory);
//设置UTF-8 编码
restTemplate.getMessageConverters().set(1, new StringHttpMessageConverter(StandardCharsets.UTF_8));
restTemplate.getInterceptors().add(new LoggingClientHttpRequestInterceptor());
return restTemplate;
}
@Slf4j
public static class LoggingClientHttpRequestInterceptor implements ClientHttpRequestInterceptor {
@Override
public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
/**
* {@link InterceptingClientHttpRequest.InterceptingRequestExecution#execute(HttpRequest, byte[])} 当拦截器链处理完,开始执行真正请求
*/
int retryCount = 1;
ClientHttpResponse response = null;
while (retryCount <= RETRY_COUNT) {
try {
long start = System.currentTimeMillis();
response = execution.execute(request, body);
log.info("[method:{}] [url:{}] [reqBody:{}] [status:{}] [time:{}]", request.getMethod(), request.getURI(), new String(body, "UTF-8"), response.getStatusCode(), System.currentTimeMillis() - start);
if(response.getStatusCode().value() != HttpStatus.OK.value()){
throw new CommonApiException("[method:" + request.getMethod() +"]" + "[url:"+ request.getURI() +"]"+"[status:"+response.getStatusCode()+"]"+"请求失败");
}
return response;
} catch (Exception e) {
if (retryCount == RETRY_COUNT) {
throw new ResourceNotFoundException("[HttpConfig]重试异常:" + e);
}
log.info("准备进行重试:[url:{}]重试第{}次", request.getURI(), retryCount);
}finally {
retryCount++;
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
log.warn("[HttpConfig] [Thread.sleep] 错误", e);
}
}
return null;
}
}
}
主要是针对restTemplate调用的接口进行重试处理,重试3次。上线后意外报错,幸好及时发现,问题不大。
分析产生报错的原因:调用的外系统接口调用404,本系统无法关闭连接资源,导致线程池超时,报错如下:
解决:报错后将连接资源关闭即可,即在catch中加入以下代码:
if (response != null) {
response.close();
}
finish!