近段時間需要優(yōu)化原有的http調(diào)用,原有的http調(diào)用是直接使用HttpClient進行調(diào)用,沒有交給spring去管理,也沒有清理過期鏈接的線程筒溃,這里記錄下使用springboot如何配置HttpClient。下面直接放代碼衰伯。
①httpclient配置類铡羡,在其中可以配置http連接池最大鏈接數(shù),并發(fā)數(shù)意鲸,超時時間烦周,代理等。
import org.apache.http.client.config.RequestConfig;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class HttpClientConfig {
private static final Logger logger = LoggerFactory.getLogger(HttpClientConfig.class);
@Value("${http.maxTotal}")
private Integer maxTotal;
@Value("${http.defaultMaxPerRoute}")
private Integer defaultMaxPerRoute;
@Value("${http.connectTimeout}")
private Integer connectTimeout;
@Value("${http.connectionRequestTimeout}")
private Integer connectionRequestTimeout;
@Value("${http.socketTimeout}")
private Integer socketTimeout;
/**
* 首先實例化一個連接池管理器怎顾,設置最大連接數(shù)读慎、并發(fā)連接數(shù)
*
* @return
*/
@Bean(name = "httpClientConnectionManager")
public PoolingHttpClientConnectionManager getHttpClientConnectionManager() {
PoolingHttpClientConnectionManager httpClientConnectionManager = new PoolingHttpClientConnectionManager();
//最大連接數(shù)
httpClientConnectionManager.setMaxTotal(maxTotal);
//并發(fā)數(shù)
httpClientConnectionManager.setDefaultMaxPerRoute(defaultMaxPerRoute);
return httpClientConnectionManager;
}
/**
* 實例化連接池,設置連接池管理器槐雾。
* 這里需要以參數(shù)形式注入上面實例化的連接池管理器
*
* @param httpClientConnectionManager
* @return
*/
@Bean(name = "httpClientBuilder")
public HttpClientBuilder getHttpClientBuilder(@Qualifier("httpClientConnectionManager") PoolingHttpClientConnectionManager httpClientConnectionManager) {
//HttpClientBuilder中的構(gòu)造方法被protected修飾夭委,所以這里不能直接使用new來實例化一個HttpClientBuilder,可以使用HttpClientBuilder提供的靜態(tài)方法create()來獲取HttpClientBuilder對象
HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
httpClientBuilder.setConnectionManager(httpClientConnectionManager);
return httpClientBuilder;
}
/**
* 注入連接池募强,用于獲取httpClient
*
* @param httpClientBuilder
* @return
*/
@Bean(name = "httpClient")
public CloseableHttpClient getCloseableHttpClient(@Qualifier("httpClientBuilder") HttpClientBuilder httpClientBuilder) {
return httpClientBuilder.build();
}
/**
* Builder是RequestConfig的一個內(nèi)部類
* 通過RequestConfig的custom方法來獲取到一個Builder對象
* 設置builder的連接信息
* 這里還可以設置proxy株灸,cookieSpec等屬性。有需要的話可以在此設置
*
* @return
*/
@Bean(name = "builder")
public RequestConfig.Builder getBuilder() {
RequestConfig.Builder builder = RequestConfig.custom();
return builder.setConnectTimeout(connectTimeout)
.setConnectionRequestTimeout(connectionRequestTimeout)
.setSocketTimeout(socketTimeout);
}
/**
* 使用builder構(gòu)建一個RequestConfig對象
*
* @param builder
* @return
*/
@Bean
public RequestConfig getRequestConfig(@Qualifier("builder") RequestConfig.Builder builder) {
return builder.build();
}
}
②清理失效的http鏈接
@Component
public class IdleConnectionEvictor extends Thread {
@Autowired
private HttpClientConnectionManager httpClientConnectionManager;
private volatile boolean shutdown;
public IdleConnectionEvictor() {
super();
super.start();
}
@Override
public void run() {
try {
while (!shutdown) {
synchronized (this) {
wait(5000);
// 關閉失效的連接
httpClientConnectionManager.closeExpiredConnections();
httpClientConnectionManager.closeIdleConnections(30L, TimeUnit.SECONDS);
}
}
} catch (InterruptedException ex) {
// 結(jié)束
}
}
//關閉清理無效連接的線程
public void shutdown() {
shutdown = true;
synchronized (this) {
notifyAll();
}
}
}
③進行調(diào)用擎值,這里暫時提供get請求慌烧,post請求可以自己封裝
@Service
public class HttpClientService {
private static final Logger logger = LoggerFactory.getLogger(HttpClientService.class);
@Autowired
private CloseableHttpClient httpClient;
@Autowired
private RequestConfig requestConfig;
/**
* get請求
*
* @return
*/
public String doGet(String url, String charset) {
CloseableHttpResponse response = null;
try {
//發(fā)送get請求
HttpGet request = new HttpGet(url);
request.setConfig(requestConfig);
response = httpClient.execute(request);
/**請求發(fā)送成功,并得到響應**/
if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
/**讀取服務器返回過來的json字符串數(shù)據(jù)**/
String strResult = EntityUtils.toString(response.getEntity());
strResult = new String(strResult.getBytes(charset), "utf-8");
return strResult;
}
} catch (IOException e) {
logger.error("http調(diào)用出錯:{}",e.getMessage())
} finally {
try {
if (response != null){
response.close();
}
}catch (IOException e){
logger.error("關閉鏈接出錯:{}",e.getMessage());
}
}
return null;
}
}
④配置文件
#http配置服務
#最大連接數(shù)
http.maxTotal = 300
#并發(fā)數(shù)
http.defaultMaxPerRoute = 300
#創(chuàng)建連接的最長時間
http.connectTimeout=3000
#從連接池中獲取到連接的最長時間
http.connectionRequestTimeout=1000
#數(shù)據(jù)傳輸?shù)淖铋L時間
http.socketTimeout=3000