Springs RestTemplate 默认连接池

Posted

技术标签:

【中文标题】Springs RestTemplate 默认连接池【英文标题】:Springs RestTemplate default connection pool 【发布时间】:2017-10-26 14:18:48 【问题描述】:

只是想知道开箱即用的 RestTemplate 是使用连接池还是每次都建立一个新连接?

【问题讨论】:

【参考方案1】:

我相信RestTemplate 不使用连接池来发送请求,它使用SimpleClientHttpRequestFactory 包装标准JDKHttpURLConnection 打开和关闭连接。

确实,您可以将 RestTemplate 配置为使用池实现,例如 HttpComponentsClientHttpRequestFactory,但很可能您还需要配置一些设置以防止请求超时。

我已经在Troubleshooting Spring's RestTemplate Requests Timeout写了关于这个问题的博客

【讨论】:

如果我使用池,是否需要创建我的 resttemplate bean 作为原型? @EugeneMakarenko 不。您打算实例化多少个 RestTemplate 实例? 我需要 10 个 RestTemplates 用于每个服务用于数据传输,5 个 RestTemplates 用于身份验证服务。如果我要使用您文章中的连接池,是否需要将这些 bean 作为单例注入到我的服务中,或者使用每个请求的原型范围创建?我不明白池将如何返回使用过的 RestTemplate。 @EugeneMakarenko,你为什么需要 10 个实例? RestTemplate 是线程安全的。您可以使用相同的 RestTemplate 实例向多个服务发送请求。只需正确配置它,这样一个慢速服务就不会劫持整个池。 谢谢!我错了。我有另一个问题。我使用两种类型的 RestTemplates。第一个配置用于授权,第二个用于数据接收。我可以为他们使用一个连接池吗?【参考方案2】:

是的,Spring RestTemplateBuilder 使用 apache httpclient 进行池化 (usage)。 RestTemplateBuilder 创建 HttpComponentsClientHttpRequestFactory 并使用 HttpClientBuilder。 HttpClientBuilder是最有趣的(source):

                s = System.getProperty("http.maxConnections", "5"); 
                int max = Integer.parseInt(s); 
                poolingmgr.setDefaultMaxPerRoute(max); 
                poolingmgr.setMaxTotal(2 * max); 

因此,默认情况下,每个路由(主机)的池大小等于 5。总池大小 = 10。 要检查连接池日志记录设置日志记录级别如下:

org.apache.http.impl.conn.PoolingHttpClientConnectionManager=TRACE

【讨论】:

【参考方案3】:

默认情况下,RestTemplate 每次都会创建新的 Httpconnection,并在完成后关闭连接。

如果您需要在 rest 模板下进行连接池,那么您可以使用不同的 ClientHttpRequestFactory 实现来池连接。

new RestTemplate(new HttpComponentsClientHttpRequestFactory())

【讨论】:

其实,没那么简单。每个 RestTemplate 都有连接池:HttpComponentsClientHttpRequestFactory->HttpClients.createSystem()->HttpClientBuilder->PoolingHttpClientConnectionManager【参考方案4】:

您可以为RestTemplate 创建一个 Bean 并在那里进行配置:

    @Bean
    public RestTemplate restTemplate() 
        PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager();
        connectionManager.setMaxTotal(100);
        connectionManager.setDefaultMaxPerRoute(20);

    RequestConfig requestConfig = RequestConfig
        .custom()
        .setConnectionRequestTimeout(5000) // timeout to get connection from pool
        .setSocketTimeout(5000) // standard connection timeout
        .setConnectTimeout(5000) // standard connection timeout
        .build();

    HttpClient httpClient = HttpClientBuilder.create()
                                             .setConnectionManager(connectionManager)
                                             .setDefaultRequestConfig(requestConfig).build();

    ClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(httpClient);


    return new RestTemplate(requestFactory);

你可以做很多配置。参考https://hc.apache.org/httpcomponents-client-ga/httpclient/apidocs/org/apache/http/impl/client/HttpClientBuilder.html

编辑

如果您想使用微米度量,您还应该使用RestTemplateBuilder 来构建 RestTemplate。

【讨论】:

我非常喜欢您的解决方案,我想提出 2 项改进建议:1. 使用 RestTemplateBuilder 2. 还设置 setConnectTimeout() 我可以编辑您的答案还是最好单独发布一个答案?跨度> 如有需要请及时更新,欢迎提出建议和改进 我建议设置一个小的 ConnectionRequestTimeout(例如 100 毫秒)。这是客户端等待从池中获取连接的时间。如果它在 100 毫秒内没有获得连接,则会引发异常。在某些情况下,这可能是对额外断路器的简单替换。别人怎么看?【参考方案5】:

我们可以在spring的rest模板下使用okhttpclient来使用连接池。下面有一个详细的博客

https://www.bytesville.com/changing-httpclient-in-spring-resttemplate/

【讨论】:

确实,OkHttp 是一个不错的替代实现。功能集也不同。例如。如果您需要读取超时,则使用 Apache HttpClient (***.com/a/6764373/193705) 是不可行的,但使用 OkHttp 是不可行的。 Apache 的客户端也可能具有独特的功能。在每种情况下,它都被广泛使用——可以说是“经过实战考验”。

以上是关于Springs RestTemplate 默认连接池的主要内容,如果未能解决你的问题,请参考以下文章

如何在spring boot应用程序中配置Jackson而不覆盖纯java中的springs默认设置

RestTemplate使用

resttemplatebuilder 在哪个jar包

SpringBoot26 RestTemplateWebClient

RestTemplate使用HttpClient连接池

RestTemplate线程安全吗?