spring-boot RestTemplate 连接池
以前我们项目都是基于 Apache HttpClient 连接池进行 web 接口调用,后来用 spring-boot, 发现 RestTemplate 挺好用。
简单介绍下:
什么是 RestTemplate?
RestTemplate 是 Spring 提供的用于访问 Rest 服务的客户端,RestTemplate 提供了多种便捷访问远程 Http 服务的方法,能够大大提高客户端的编写效率。
调用 RestTemplate 的默认构造函数,RestTemplate 对象在底层通过使用 java.net 包下的实现创建 HTTP 请求,可以通过使用 ClientHttpRequestFactory 指定不同的 HTTP 请求方式。
ClientHttpRequestFactory 接口主要提供了两种实现方式
一种是 SimpleClientHttpRequestFactory,使用 J2SE 提供的方式(既 java.net 包提供的方式)创建底层的 Http 请求连接。
第二种方式是使用 HttpComponentsClientHttpRequestFactory 方式,底层使用 HttpClient 访问远程的 Http 服务,使用 HttpClient 可以配置连接池和证书等信息。
RestTemplate 默认是使用 SimpleClientHttpRequestFactory,内部是调用 jdk 的 HttpConnection,默认超时为 -1
下面我介绍下 spring-boot 如何配置 RestTemplate 连接池 (github):
import org.apache.http.client.HttpClient; import org.apache.http.client.config.RequestConfig; import org.apache.http.config.Registry; import org.apache.http.config.RegistryBuilder; import org.apache.http.conn.socket.ConnectionSocketFactory; import org.apache.http.conn.socket.PlainConnectionSocketFactory; import org.apache.http.conn.ssl.SSLConnectionSocketFactory; import org.apache.http.impl.client.HttpClientBuilder; import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.client.ClientHttpRequestFactory; import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; import org.springframework.web.client.RestTemplate;@Configuration
public class RestTemplateConfig {@Bean </span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> RestTemplate restTemplate() { </span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> RestTemplate(httpRequestFactory()); } @Bean </span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> ClientHttpRequestFactory httpRequestFactory() { </span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> HttpComponentsClientHttpRequestFactory(httpClient()); } @Bean </span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> HttpClient httpClient() { Registry</span><ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory><span style="color: rgba(0, 0, 0, 1)">create() .register(</span>"http"<span style="color: rgba(0, 0, 0, 1)">, PlainConnectionSocketFactory.getSocketFactory()) .register(</span>"https"<span style="color: rgba(0, 0, 0, 1)">, SSLConnectionSocketFactory.getSocketFactory()) .build(); PoolingHttpClientConnectionManager connectionManager </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> PoolingHttpClientConnectionManager(registry); </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">设置整个连接池最大连接数 根据自己的场景决定</span> connectionManager.setMaxTotal(200<span style="color: rgba(0, 0, 0, 1)">); </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">路由是对maxTotal的细分</span> connectionManager.setDefaultMaxPerRoute(100<span style="color: rgba(0, 0, 0, 1)">); RequestConfig requestConfig </span>=<span style="color: rgba(0, 0, 0, 1)"> RequestConfig.custom() .setSocketTimeout(</span>10000) <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">服务器返回数据(response)的时间,超过该时间抛出read timeout</span> .setConnectTimeout(5000)<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">连接上服务器(握手成功)的时间,超出该时间抛出connect timeout</span> .setConnectionRequestTimeout(1000)<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">从连接池中获取连接的超时时间,超过该时间未拿到可用连接,会抛出org.apache.http.conn.ConnectionPoolTimeoutException: Timeout waiting for connection from pool</span>
.build();
return HttpClientBuilder.create()
.setDefaultRequestConfig(requestConfig)
.setConnectionManager(connectionManager)
.build();
}
}