restTemplate设置httpClient线程池
Posted 好大的月亮
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了restTemplate设置httpClient线程池相关的知识,希望对你有一定的参考价值。
第一步肯定是先引入依赖
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.7</version>
</dependency>
java连接池配置类
常量类
package com.fchen.usercenter.config;
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
@Data
public class HttpPoolConstants {
@Value("${httpPool.restTemplateCharset:utf-8}")
private String restTemplateCharset;
@Value("${httpPool.poolMaxSize:500}")
private Integer poolMaxSize;
@Value("${httpPool.maxPerRoute:50}")
private Integer maxPerRoute;
@Value("${httpPool.requestConfig.socketTimeout:10000}")
private Integer socketTimeout;
@Value("${httpPool.requestConfig.connectTimeout:5000}")
private Integer connectTimeout;
@Value("${httpPool.requestConfig.connectionRequestTimeout:1000}")
private Integer connectionRequestTimeout;
@Value("${httpPool.maxIdleTime:5000}")
private Integer maxIdleTime;
@Value("${httpPool.defaultKeepAliveTime:10000}")
private Integer defaultKeepAliveTime;
@Value("${httpPool.specialKeepAliveTimeHostName:''}")
private String specialKeepAliveTimeHostName;
}
连接池配置类,主要是制造出连接池的ClientHttpRequestFactory
package com.fchen.usercenter.config;
import com.alibaba.fastjson.JSON;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HeaderElement;
import org.apache.http.HeaderElementIterator;
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.ConnectionKeepAliveStrategy;
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.apache.http.message.BasicHeaderElementIterator;
import org.apache.http.protocol.HTTP;
import org.springframework.beans.factory.annotation.Autowired;
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 java.util.concurrent.TimeUnit;
@Configuration
@Slf4j
public class HttpClientPoolConfig {
@Autowired
private HttpPoolConstants httpPoolConstants;
private ObjectMapper objectMapper;
{
objectMapper = new ObjectMapper();
}
@Bean("restHttpRequestFactory")
public ClientHttpRequestFactory httpRequestFactory() {
return new HttpComponentsClientHttpRequestFactory(httpClient());
}
@Bean("restHttpClient")
public HttpClient httpClient() {
Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
.register("http", PlainConnectionSocketFactory.getSocketFactory())
.register("https", SSLConnectionSocketFactory.getSocketFactory())
.build();
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(registry);
//设置整个连接池最大连接数 根据自己的场景决定
connectionManager.setMaxTotal(httpPoolConstants.getPoolMaxSize());
//路由是对maxTotal的细分,针对一个url的最大并发数,每路由最大连接数,默认值是2
connectionManager.setDefaultMaxPerRoute(httpPoolConstants.getMaxPerRoute());
//针对所有的请求设置超时时间,也可以放到后面针对某一个url设置这些个超时时间
RequestConfig requestConfig = RequestConfig.custom()
.setSocketTimeout(httpPoolConstants.getSocketTimeout()) //服务器返回数据(response)的时间,超过该时间抛出read timeout
.setConnectTimeout(httpPoolConstants.getConnectTimeout())//连接上服务器(握手成功)的时间,超出该时间抛出connect timeout
.setConnectionRequestTimeout(httpPoolConstants.getConnectionRequestTimeout())//从连接池中获取连接的超时时间,超过该时间未拿到可用连接,会抛出org.apache.http.conn.ConnectionPoolTimeoutException: Timeout waiting for connection from pool
.build();
/*
启动清理线程,也可以启用用CloseableHttpClient的清理线程
Thread t = new IdleConnectionMonitorThread(connectionManager);
t.setName("httpconnections-pool-evict-thread");
t.start();
*/
return HttpClientBuilder.create()
.setDefaultRequestConfig(requestConfig)
.setConnectionManager(connectionManager)
//设置后台线程剔除失效连接
.evictExpiredConnections().evictIdleConnections(httpPoolConstants.getMaxIdleTime(), TimeUnit.SECONDS)
.build();
}
}
在RestTemplate
注入到spring
上下文的时候设置ClientHttpRequestFactory
@Bean
public RestTemplate restTemplate(HttpClientPoolConfig httpClientPoolConfig){
return new RestTemplate(httpClientPoolConfig.httpRequestFactory());
}
或者直接用HttpClient直接跑post请求
这里只是截取了一段,作为demo
展示如何使用HttpClient
直接执行post
请求,但是这里要注意HttpClient
要保证是单例的,不要每次都new
一个HttpClient
URI uri = new URIBuilder(xxx).setPath(xxx).setCharset(Consts.UTF_8).build();
fileName = (null == fileName || fileName.isEmpty()) ? generateFileName() : fileName;
HttpPost httpPost = new HttpPost(uri);
httpPost.addHeader("content-type", "text/plain");
httpPost.addHeader("xxx", xxx);
httpPost.addHeader("filename", fileName);
//针对这个url的post请求设置各种超时时间
this.setRequestConfig(httpPost);
InputStreamEntity inputStreamEntity = new InputStreamEntity(inputStream);
inputStreamEntity.setContentEncoding(charsetUtf8);
httpPost.setEntity(inputStreamEntity);
// 发起请求 并返回请求的响应
CloseableHttpResponse response = httpClient.execute(httpPost);
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode >= 200 && statusCode < 300) {
if (null == response.getEntity()) {
// 说明返回结果不正确
throw new RuntimeException(fileName + " request failure:Response is empty");
}
String entity = EntityUtils.toString(response.getEntity(), Consts.UTF_8);
Result result = JSON.parseObject(entity, Result.class);
if (result.getCode() == 1 && null != result.getData() && !result.getData().isEmpty()) {
return fileName;
} else {
throw new RuntimeException(fileName + " upload failure:" + result.getCode() + "," + result.getMsg());
}
} else {
throw new RuntimeException("request failure:" + statusCode + EntityUtils.toString(response.getEntity(), Consts.UTF_8));
}
单独针对某一个url
请求设置各种超时时间
private void setRequestConfig(HttpPost httpPost) {
RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(this.socketTimeout).setSocketTimeout(this.socketTimeout).setConnectionRequestTimeout(this.connectionRequestTimeout).build();
httpPost.setConfig(requestConfig);
}
以上是关于restTemplate设置httpClient线程池的主要内容,如果未能解决你的问题,请参考以下文章
记一次解决RestTemplate和HttpClient请求结果乱码的问题
使用当前 httpclient (4.x) 的 RestTemplate 基本或摘要身份验证