Spring的RestTemplate默认连接池是什么?

41

我想知道 RestTemplate 是否默认使用连接池,还是每次都建立一个新的连接?

6个回答

40

是的,Spring RestTemplateBuilder 使用 Apache HttpClient 进行连接池管理 (用途)。 RestTemplateBuilder 创建 HttpComponentsClientHttpRequestFactory 并使用 HttpClientBuilder

HttpClientBuilder 默认每个路由(主机)设置为5个连接,总连接数为10个 (来源):

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

要检查连接池日志,请按以下方式设置日志级别:

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

2
RestTemplateBuilder?这个答案可能是正确的,但在Spring依赖项中没有看到RestTemplateBuilder。如果你使用new RestTemplate(),你会得到一个SimpleClientHttpRequestFactory而不是HttpComponentsClientHttpRequestFactory。使用new RestTemplate(HttpComponentsClientHttpRequestFactory)似乎是正确的方法。 - peerless-phreap
3
这个答案是正确的。当您浏览互联网时,如果发现不同的默认值(例如2/20或5/25),请不要感到困惑。这些默认值适用于直接实例化“PoolingHttpClientConnectionManager”(来源)。这些值也随着时间的推移而改变... 但是,正如所说,Spring Boot使用自己的默认值,即“HttpClientBuilder”。 - Peter Wippermann
@Volodymyr Kret,您在Spring的实现中找到了关于设置这两个值的任何参考吗?或者自2018年以来,Spring是否改变了策略? - Daniel Pop
1
@DanielPop 我在文档中寻找这两个配置项,但没有找到:( 不过你可以尝试将它们设置为环境变量,虽然这不是最佳实践。 - Volodymyr Kret
如果您的依赖项中包含Apache HttpClient用于连接池,并且正确使用了RestTemplateBuilder!如果在建立HTTP连接时遇到性能问题,我建议您详细调试以确保一切正常运行。 - undefined

31

我认为RestTemplate在发送请求时并不使用连接池,它使用一个SimpleClientHttpRequestFactory来包装标准的JDKHttpURLConnection以打开和关闭连接。

确实,您可以配置RestTemplate使用像HttpComponentsClientHttpRequestFactory之类的池化实现,但很可能您还需要配置一些设置以防止请求超时。

我已经在Troubleshooting Spring's RestTemplate Requests Timeout中发表了关于这个问题的博客文章。


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

19

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

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

new RestTemplate(new HttpComponentsClientHttpRequestFactory())

7
实际上,并不那么简单。每个RestTemplate都有连接池:HttpComponentsClientHttpRequestFactory->HttpClients.createSystem()->HttpClientBuilder->PoolingHttpClientConnectionManager。 - Volodymyr Kret

17

您可以为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

编辑

如果你想使用micrometer指标,你还应该使用RestTemplateBuilder来构建RestTemplate。


3
我非常喜欢你的解决方案,我想提出两个改进建议:1. 使用RestTemplateBuilder 2. 同时设置setConnectTimeout()。我可以编辑你的答案吗?还是我最好发表一个单独的答案? - Matthias M
如有需要,请更新,欢迎提出建议和改进。 - sendon1982
我建议设置一个较小的ConnectionRequestTimeout(例如100毫秒)。这是客户端等待从池中获取连接的时间。如果在100毫秒内未获得连接,则会抛出异常。在某些情况下,这可能是对额外断路器的简单替换。其他人怎么想? - Matthias M

2

如果使用配置了Apache HttpClient的Spring Boot(依赖于org.apache.httpcomponents:httpclient库)

默认情况下,已配置由PoolingHttpClientConnectionManager管理的连接池。

连接的默认并发设置(您可以在此处找到有关默认设置的更多信息:https://hc.apache.org/httpcomponents-client-4.5.x/current/tutorial/html/connmgmt.html):

PoolingHttpClientConnectionManager在每个路由和总体上维护连接数的最大限制。默认情况下,此实现将不会为给定路由创建超过2个并发连接,并且总共不会超过20个连接。对于许多真实世界的应用程序来说,这些限制可能过于约束,特别是如果它们使用HTTP作为其服务的传输协议。


1

确实,OkHttp是一个不错的替代实现。而且功能集也不同。例如,如果您需要读取超时,使用Apache HttpClient就行不通(https://dev59.com/vWw15IYBdhLWcg3wMo8Y#6764373),但使用OkHttp就可以了。Apache的客户端可能也有独特的功能。在任何情况下,它都被广泛使用 - 可以说是“经过实战考验”的。 - Peter Wippermann

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