Spring RestTemplate - 需要释放连接吗?

15

这是我的Rest Template配置,

    @Bean
    @Qualifier("myRestService")
    public RestTemplate createRestTemplate(@Value("${connection.timeout}") String maxConn) {
        PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager();
         connectionManager.setMaxTotal(maxTotalConn);
         connectionManager.setDefaultMaxPerRoute(maxPerChannel);

        RequestConfig config = RequestConfig.custom().setConnectTimeout(100000).build();
        CloseableHttpClient httpClient = HttpClientBuilder.create().setConnectionManager(connectionManager)
                .setDefaultRequestConfig(config).build();
        ClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(httpClient);

        RestTemplate restTemplate = new RestTemplate(factory);

        restTemplate.setErrorHandler(new RestResponseErrorHandler());
         restTemplate.setMessageConverters(createMessageConverters());

        return restTemplate;
    }

我正在使用PoolingHttpClientConnectionManager来管理连接。

以下是访问该连接的代码:

ResponseEntity<String> response = restClient.exchange( url, HttpMethod.GET, entity , String.class );

在上述调用之后,我是否需要释放连接或RestTemplate会处理它。如果我们需要释放连接,则需要注意。

请问有人可以解释/展示如何释放连接吗?

3个回答

23

你应该将ClientHttpRequestFactory声明为一个bean。通过将它声明为一个bean,它将成为Spring bean工厂的管理对象,当应用程序关闭或bean超出作用范围时,工厂将调用工厂的destroy方法。ClientHttpRequestFactory的销毁方法将关闭底层的ClientConnectionManager连接池。你可以查看Spring API文档了解详细信息。

@Bean
public ClientHttpRequestFactory createRequestFactory(@Value("${connection.timeout}") String maxConn) {
    PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager();
     connectionManager.setMaxTotal(maxTotalConn);
     connectionManager.setDefaultMaxPerRoute(maxPerChannel);

    RequestConfig config = RequestConfig.custom().setConnectTimeout(100000).build();
    CloseableHttpClient httpClient = HttpClientBuilder.create().setConnectionManager(connectionManager)
            .setDefaultRequestConfig(config).build();
    return new HttpComponentsClientHttpRequestFactory(httpClient);
}

然后您可以使用此bean创建RestTemplate:

@Bean
@Qualifier("myRestService")
public RestTemplate createRestTemplate(ClientHttpRequestFactory factory) {
    RestTemplate restTemplate = new RestTemplate(factory);

    restTemplate.setErrorHandler(new RestResponseErrorHandler());
    restTemplate.setMessageConverters(createMessageConverters());

    return restTemplate;
}

1
请问您能否更清楚地解释一下,最好附上代码示例。 - Umar

17

你提出的问题是:

在以上调用之后,我是否需要释放连接,或者RestTemplate会自动处理?如果我们需要负责释放连接。

不需要,在使用resttemplate时,你不需要关闭响应中的连接。

从apache httpclient来看,你需要消耗完整个响应(EntityUtils.consume(HttpEntity))并关闭响应。

这可以在ClientConnectionRelease.java中验证。

但是RestTemplate会为您完成这项工作,要验证相同的内容,请查看RestTemplate.java

查找方法

protected <T> T doExecute(URI url,...) {
 try {
        ClientHttpRequest request = this.createRequest(url, method);
        ...
        response = request.execute();
        ...
        if(responseExtractor != null) {
            var7 = responseExtractor.extractData(response);
            return var7;
        }
       ...
       ...
    } finally {
        if(response != null) {
            response.close();
        }

    }
}

当使用responseExtractor.extractData(response);消耗响应时,响应提取器会为您完成工作。

提取完整数据后,它还会关闭response.close()。


1
他的整个观点是不要为每个调用关闭连接,而是使用Apache PoolingHttpClientConnectionManager来保持套接字开放? - Kalpesh Soni
Deepak是正确的。他需要关闭连接以将其释放回连接池。 - cwa
1
我们正在使用ClientHttpRequestInterceptor拦截RestTemplate,但是在某些异常情况下,响应没有被关闭。 - hipokito
1
嗨,当响应为null时会发生什么? - Alaf Azam
当池子里的资源 [总可用: 5; 分配路由: 50 of 50; 总分配: 18 of 100] 开始出现超时问题时,它使用了具有 MaxTotal 100 和 DefaultMaxPerRoute 50 配置的PoolingHttpClientConnectionManager,同时还使用了 ConnectionKeepAliveStrategy(保持连接时间为20秒),那么可能的错误是什么? - Tiago Medici
显示剩余2条评论

0

我认为答案在这里:org.springframework.remoting.httpinvoker.HttpComponentsHttpInvokerRequestExecutor#doExecuteRequest

    @Override
    protected RemoteInvocationResult doExecuteRequest(
            HttpInvokerClientConfiguration config, ByteArrayOutputStream baos)
            throws IOException, ClassNotFoundException {

        HttpPost postMethod = createHttpPost(config);
        setRequestBody(config, postMethod, baos);
        try {
            HttpResponse response = executeHttpPost(config, getHttpClient(), postMethod);
            validateResponse(config, response);
            InputStream responseBody = getResponseBody(config, response);
            return readRemoteInvocationResult(responseBody, config.getCodebaseUrl());
        }
        finally {
            postMethod.releaseConnection();
        }
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接