Springs RestTemplate 默认连接池
Posted
技术标签:
【中文标题】Springs RestTemplate 默认连接池【英文标题】:Springs RestTemplate default connection pool 【发布时间】:2017-10-26 14:18:48 【问题描述】:只是想知道开箱即用的 RestTemplate 是使用连接池还是每次都建立一个新连接?
【问题讨论】:
【参考方案1】:我相信RestTemplate
不使用连接池来发送请求,它使用SimpleClientHttpRequestFactory
包装标准JDK
的HttpURLConnection
打开和关闭连接。
确实,您可以将 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默认设置