Spring boot RestTemplate关闭空响应连接会导致ConnectionPoolTimeoutExceptions
我们有一个spring引导应用程序,它对一组后端进行RESTFul调用,其中一个有时返回空响应,我们观察到在这些实例中连接没有被释放,因为RestTemplate类中的代码:Spring boot RestTemplate关闭空响应连接会导致ConnectionPoolTimeoutExceptions,spring,spring-boot,httpconnection,spring-resttemplate,Spring,Spring Boot,Httpconnection,Spring Resttemplate,我们有一个spring引导应用程序,它对一组后端进行RESTFul调用,其中一个有时返回空响应,我们观察到在这些实例中连接没有被释放,因为RestTemplate类中的代码: protected <T> T doExecute(URI url, HttpMethod method, RequestCallback requestCallback, ResponseExtractor<T> responseExtractor) throws Rest
protected <T> T doExecute(URI url, HttpMethod method, RequestCallback requestCallback,
ResponseExtractor<T> responseExtractor) throws RestClientException {
Assert.notNull(url, "'url' must not be null");
Assert.notNull(method, "'method' must not be null");
ClientHttpResponse response = null;
try {
ClientHttpRequest request = createRequest(url, method);
if (requestCallback != null) {
requestCallback.doWithRequest(request);
}
response = request.execute();
handleResponse(url, method, response);
if (responseExtractor != null) {
return responseExtractor.extractData(response);
}
else {
return null;
}
}
catch (IOException ex) {
String resource = url.toString();
String query = url.getRawQuery();
resource = (query != null ? resource.substring(0, resource.indexOf('?')) : resource);
throw new ResourceAccessException("I/O error on " + method.name() +
" request for \"" + resource + "\": " + ex.getMessage(), ex);
}
finally {
if (response != null) {
response.close();
}
}
}
受保护的不执行(URI url、HttpMethod方法、RequestCallback、RequestCallback、,
ResponseExtractor(ResponseExtractor)抛出RestClientException{
Assert.notNull(url,“'url'不能为null”);
Assert.notNull(方法,“'method'不能为null”);
ClientHttpResponse响应=null;
试一试{
ClientHttpRequest请求=createRequest(url,方法);
if(requestCallback!=null){
requestCallback.doWithRequest(请求);
}
response=request.execute();
HandlerResponse(url、方法、响应);
if(responseExtractor!=null){
返回responseExtractor.extractData(响应);
}
否则{
返回null;
}
}
捕获(IOEX异常){
String resource=url.toString();
String query=url.getRawQuery();
resource=(query!=null?resource.substring(0,resource.indexOf('?')):resource);
抛出新的ResourceAccessException(“+method.name()上的I/O错误)+
“请求\”“+resource+”\:“+ex.getMessage(),ex);
}
最后{
if(响应!=null){
response.close();
}
}
}
当响应为null或出错时,有没有办法释放连接或使用内容
编辑以添加导致错误的代码:
MyHttpClientClass{
private X getResponseBody(RestClient client, URI uri, HttpMethod method, HttpEntity<T> entity, Class<R> responseType, MyErrorHandler errorHandler) {
try
{ String host = this.getHost();
ResponseEntity<X> resp = client.exchange(uri, method, entity, responseType);
return resp.getBody();
} catch (HttpServerErrorException | HttpClientErrorException e)
{ handleHttpException(e, errorHandler);
throw e;
} catch (Exception e) {
log(e);
throw e; } } }
-----------
Class1 implements Callable<T>
{
@Override public T doCall() throws Exception {
try
{ return this.getRestClient().exchange(this.getUri(),
this.getHttpMethod(), this.getEntity(), getResponseType()).getBody(); } catch (HttpClientErrorException ex) { throw ex; } catch (HttpStatusCodeException ex) { if(this.isNeededRetry(ex)) { throw ex; }else { return generateErrorResponse(ex).getBody(); } } catch (RestClientException ex) { throw ex; } catch (Exception ex) { throw ex; } } }
----------
MySpringApplicationClass{
public X get(String api, String params, Class<R> responseType, String path, List<String> pathVariables, MyErrorHandler errorHandler)
{
return getResponseBody(...);
}}
MyHttpClientClass{
私有X getResponseBody(RestClient客户端、URI URI、HttpMethod方法、HttpEntity实体、类responseType、MyErrorHandler errorHandler){
尝试
{String host=this.getHost();
ResponseEntity resp=client.exchange(uri、方法、实体、responseType);
返回相应的getBody();
}捕获(HttpServerErrorException | HttpClientErrorException)
{handleHttpException(e,errorHandler);
投掷e;
}捕获(例外e){
日志(e);
抛出e;}}}
-----------
Class1实现了可调用的
{
@重写公共T doCall()引发异常{
尝试
{返回this.getRestClient().exchange(this.getUri(),
this.getHttpMethod()、this.getEntity()、getResponseType()).getBody();}catch(HttpClientErrorException ex){throw ex;}catch(HttpStatusCodeException ex){if(this.isNeedRetry(ex)){throw ex;}else{返回generateErrorResponse(ex).getBody();}}catch(RestClientException ex){throw ex;}catch(Exception ex){throw ex;}}}
----------
MySpringApplication类{
公共X获取(字符串api、字符串参数、类响应类型、字符串路径、列表路径变量、MyErrorHandler errorHandler)
{
返回getResponseBody(…);
}}
当响应为空时,您将如何使用它?是的,不确定。在这种情况下,我们应该如何处理连接释放?我们无法控制后端返回的内容。抱歉,我弄糊涂了。我认为答案的主体是空的,因此写下了我的答案。由于这是restemplate
code,我们实际上无法修改底层逻辑。你能展示你的代码吗?这就是我们如何使用restClient对象(它扩展了RestTemplate)`public T myExceute抛出异常{try{return getRestClient().exchange(request.getUri(),request.getHttpMethod(),request.getEntity(),request.getResponseType()).getBody();}catch(httpclienterorException ex){throw-ex;}catch(HttpStatusCodeException-ex){if(this.isneedRetry(ex)){throw-ex;….}catch(RestClientException-ex){throw-ex;}catch(Exception-ex){throw-ex;}}}`(抱歉,无法格式化)尝试{return getRestClient().exchange(request.getUri(),request.getHttpMethod(),request.getEntity(),request.getResponseType()).getBody();}catch(HttpClientErrorException ex){throw ex;}catch(HttpStatusCodeException ex){throw ex;}….}catch(RestClientException ex){throw ex;}catch(Exception ex){throw ex;}
当响应为空时,您将如何使用响应?是的,不确定。在这种情况下,我们应该如何处理连接释放?我们无法控制后端返回的内容。很抱歉,我感到困惑。我认为响应的主体为空,并相应地编写了我的答案。由于这是RestTemplate
代码,我们实际上无法修改底层逻辑。你能展示你的代码吗?这就是我们如何使用restClient对象(它扩展了RestTemplate)`public T myExceute抛出异常{try{return getRestClient().exchange(request.getUri(),request.getHttpMethod(),request.getEntity(),request.getResponseType()).getBody();}catch(HttpClientErrorException ex){throw ex;}catch(HttpStatusCodeException ex){if(this.isneedRetry(ex)){throw ex;….}catch(RestClientException ex){throw ex;}catch(Exception ex){throw ex;}}`(抱歉,无法格式化)尝试{return getRestClient().exchange(request.getUri(),request.getHttpMethod(),request.getEntity(),request.getResponseType()).getBody();}catch(HttpClientErrorException ex){throw ex;}catch(HttpStatusCodeException ex){throw ex;}….}catch(RestClientException ex){throw ex;}catch(Exception ex){throw ex;}catch(Exception ex){throw ex;}/co