AsyncRestTemplate 连接池配置
通常业务中的 HTTP 请求都是同步调用的。如果请求响应比较慢,甚至请求超时,程序就必须等到请求返回以后才能继续执行,在某些场合下,我并不需要等待请求的结果,或者我不关心请求是否执行成功,需要继续执行之后的逻辑,就需要通过异步处理。
AsyncRestTemplate
是实现异步调用的工具。
AsyncRestTemplate
的连接池实现如下
配置文件类
/**
* RestTemplate 客户端 Httpclient 的线程池配置
*
* @author fengxuechao
* @version 0.1
* @date 2019/11/12
*/@ConfigurationProperties(prefix="http-pool")@DatapublicclassHttpPoolProperties{/**
* 最大线程数
*/private Integer maxTotal=20;/**
* 默认线程数
*/private Integer defaultMaxPerRoute=10;/**
* 连接上服务器(握手成功)的时间
*/private Integer connectTimeout=1000;/**
* 从连接池中获取连接的超时时间
*/private Integer connectionRequestTimeout=3000;/**
* 服务器返回数据(response)的时间
*/private Integer socketTimeout=5000;/**
* 用于校验线程空闲的时间
*/private Integer validateAfterInactivity=7000;/**
* 开启异步线程池
*/private Boolean async=false;}
连接池配置类
忽略SSL
/**
* @author fengxuechao
* @version 0.1
* @date 2019/12/17
*/@Slf4j@ComponentpublicclassHttpClientHelper{public SSLContextgetSslContext(){// 在调用SSL之前需要重写验证方法,取消检测SSL
X509TrustManager trustManager=newX509TrustManager(){@Overridepublic X509Certificate[]getAcceptedIssuers(){return null;}@OverridepublicvoidcheckClientTrusted(X509Certificate[] xcs, String str){}@OverridepublicvoidcheckServerTrusted(X509Certificate[] xcs, String str){}};
SSLContext ctx= null;try{
ctx= SSLContext.getInstance(SSLConnectionSocketFactory.TLS);
ctx.init(null,newTrustManager[]{trustManager}, null);}catch(NoSuchAlgorithmException| KeyManagementException e){
log.error("创建 SSL 失败", e);}assert ctx!= null;return ctx;}}
配置类
/**
* @author fengxuechao
* @version 0.1
* @date 2019/12/17
*/@Slf4j@Configuration@ConditionalOnClass({HttpAsyncClient.class})@ConditionalOnProperty(prefix="http-pool", name="async", havingValue="true")@EnableConfigurationProperties(HttpPoolProperties.class)publicclassHttpAsyncClientConfig{@Autowiredprivate HttpPoolProperties httpPoolProperties;@Autowiredprivate HttpClientHelper helper;/**
* 异步 Http 连接池
*
* @return
*/@Bean@ConditionalOnMissingBean(AsyncClientHttpRequestFactory.class)public AsyncClientHttpRequestFactoryasyncClientHttpRequestFactory(){
HttpComponentsAsyncClientHttpRequestFactory factory=newHttpComponentsAsyncClientHttpRequestFactory(httpAsyncClient());
factory.setConnectTimeout(httpPoolProperties.getConnectTimeout());
factory.setReadTimeout(httpPoolProperties.getSocketTimeout());
factory.setConnectionRequestTimeout(httpPoolProperties.getConnectionRequestTimeout());return factory;}/**
* 异步 Http 客户端
*
* @return
*/@Bean("httpAsyncClient")@ConditionalOnMissingBean(HttpAsyncClient.class)public HttpAsyncClienthttpAsyncClient(){
SSLContext sslContext= helper.getSslContext();
Registry<SchemeIOSessionStrategy> registry= RegistryBuilder.<SchemeIOSessionStrategy>create().register("http", NoopIOSessionStrategy.INSTANCE).register("https",newSSLIOSessionStrategy(sslContext)).build();
ConnectingIOReactor ioReactor= null;try{
ioReactor=newDefaultConnectingIOReactor();}catch(IOReactorException e){
log.error("构建异步连接失败", e);}assert ioReactor!= null;
PoolingNHttpClientConnectionManager connectionManager=newPoolingNHttpClientConnectionManager(ioReactor, registry);
connectionManager.setMaxTotal(httpPoolProperties.getMaxTotal());
connectionManager.setDefaultMaxPerRoute(httpPoolProperties.getDefaultMaxPerRoute());
RequestConfig requestConfig= RequestConfig.custom()//服务器返回数据(response)的时间,超过抛出read timeout.setSocketTimeout(httpPoolProperties.getSocketTimeout())//连接上服务器(握手成功)的时间,超出抛出connect timeout.setConnectTimeout(httpPoolProperties.getConnectTimeout())//从连接池中获取连接的超时时间,超时间未拿到可用连接,会抛出org.apache.http.conn.ConnectionPoolTimeoutException: Timeout waiting for connection from pool.setConnectionRequestTimeout(httpPoolProperties.getConnectionRequestTimeout()).build();return HttpAsyncClientBuilder.create().setDefaultRequestConfig(requestConfig).setConnectionManager(connectionManager).build();}}
AsyncRestTemplate 配置
/**
* @author fengxuechao
* @version 0.1
* @date 2019/11/12
*/@Configuration@Import({HttpClientConfig.class})publicclassRestTemplateAutoConfiguration{/**
* 异步 RestTemplate
*
* @return
*/@Bean("asyncRestTemplate")@ConditionalOnMissingBean@ConditionalOnBean(value={AsyncClientHttpRequestFactory.class, ClientHttpRequestFactory.class})public AsyncRestTemplateasyncRestTemplate(
AsyncClientHttpRequestFactory asyncClientHttpRequestFactory,
ClientHttpRequestFactory httpRequestFactory){
RestTemplate restTemplate=newRestTemplate(httpRequestFactory);
restTemplate.getMessageConverters().set(1,newStringHttpMessageConverter(StandardCharsets.UTF_8));returnnewAsyncRestTemplate(asyncClientHttpRequestFactory, restTemplate);}}