restTemplate实现ClientHttpRequestInterceptor,报错org.apache.http.conn.ConnectionPoolTimeoutException: Timeout waiting for connection from pool
代码如下:
@Configuration
public class HttpConfig {private static final Integer RETRY_COUNT = 3;@Beanpublic 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;}@Slf4jpublic static class LoggingClientHttpRequestInterceptor implements ClientHttpRequestInterceptor {@Overridepublic 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!