緊接上一節(jié)亿鲜,本節(jié)記錄 【連接池的配置】
兩個主機建立連接的過程是很復雜的一個過程冤吨,涉及到多個數(shù)據(jù)包的交換
漩蟆,并且也很耗時間怠李。Http連接需要的三次握手
開銷很大,這一開銷對于比較小的http消息來說更大夷蚊。但是如果我們直接使用已經(jīng)建立好的http連接惕鼓,這樣花費就比較小唐础,吞吐率更大彻犁。
修改代碼
在上節(jié)代碼的基礎(chǔ)上汞幢,我們添加全局靜態(tài)變量連接池管理對象
森篷,提供靜態(tài)代碼塊初始化連接池管理對象.
- 初始化
......前省略
/**
* Http請求工具類
*
* @author 大漠知秋
*/
public class HttpRequestUtils {
/** 全局連接池對象 */
private static final PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager();
/**
* 靜態(tài)代碼塊配置連接池信息
*/
static {
// 設置最大連接數(shù)
connManager.setMaxTotal(200);
// 設置每個連接的路由數(shù)
connManager.setDefaultMaxPerRoute(20);
}
/**
* 獲取Http客戶端連接對象
*
* @param timeOut 超時時間
* @return Http客戶端連接對象
*/
public static CloseableHttpClient getHttpClient(Integer timeOut) {
......后省略
PoolingHttpClientConnectionManager是個復雜的類仲智,它管理著
連接池
钓辆,可以同時為很多線程提供http連接請求。當請求一個新的連接時前联,如果連接池有可用的持久連接,連接管理器就會使用其中的一個啸臀,而不是再創(chuàng)建一個新的連接乘粒。
PoolingHttpClientConnectionManager維護的連接數(shù)在每個路由基礎(chǔ)和總數(shù)上都有限制灯萍。默認旦棉,每個路由基礎(chǔ)上的連接不超過2個,總連接數(shù)不能超過20他爸。在實際應用中诊笤,這個限制可能會太小了讨跟,尤其是當服務器也使用Http協(xié)議時晾匠。此處我們設置為最高
200
個總連接數(shù)和每個基礎(chǔ)路由連接不超過20
個凉馆。
- 已經(jīng)在全局聲明Http連接池管理工具澜共,配置進httpClient連接客戶端
/**
* 獲取Http客戶端連接對象
*
* @param timeOut 超時時間
* @return Http客戶端連接對象
*/
public static CloseableHttpClient getHttpClient(Integer timeOut) {
// 創(chuàng)建Http請求配置參數(shù)
RequestConfig requestConfig = RequestConfig.custom()
// 獲取連接超時時間
.setConnectionRequestTimeout(timeOut)
// 請求超時時間
.setConnectTimeout(timeOut)
// 響應超時時間
.setSocketTimeout(timeOut)
.build();
/**
* 測出超時重試機制為了防止超時不生效而設置
* 如果直接放回false,不重試
* 這里會根據(jù)情況進行判斷是否重試
*/
HttpRequestRetryHandler retry = new HttpRequestRetryHandler() {
@Override
public boolean retryRequest(IOException exception, int executionCount, HttpContext context) {
if (executionCount >= 3) {// 如果已經(jīng)重試了3次嗦董,就放棄
return false;
}
if (exception instanceof NoHttpResponseException) {// 如果服務器丟掉了連接奇唤,那么就重試
return true;
}
if (exception instanceof SSLHandshakeException) {// 不要重試SSL握手異常
return false;
}
if (exception instanceof InterruptedIOException) {// 超時
return true;
}
if (exception instanceof UnknownHostException) {// 目標服務器不可達
return false;
}
if (exception instanceof ConnectTimeoutException) {// 連接被拒絕
return false;
}
if (exception instanceof SSLException) {// ssl握手異常
return false;
}
HttpClientContext clientContext = HttpClientContext.adapt(context);
HttpRequest request = clientContext.getRequest();
// 如果請求是冪等的咬扇,就再次嘗試
if (!(request instanceof HttpEntityEnclosingRequest)) {
return true;
}
return false;
}
};
// 創(chuàng)建httpClient
return HttpClients.custom()
// 把請求相關(guān)的超時信息設置到連接客戶端
.setDefaultRequestConfig(requestConfig)
// 把請求重試設置到連接客戶端
.setRetryHandler(retry)
// 配置連接池管理對象
.setConnectionManager(connManager)
.build();
}
在上方創(chuàng)建httpClient
處把連接池管理對象配置到連接客戶端中
- 最后完整代碼
package com.lynchj.writing;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.net.UnknownHostException;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLHandshakeException;
import org.apache.http.HttpEntity;
import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpRequest;
import org.apache.http.NoHttpResponseException;
import org.apache.http.ParseException;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.EntityUtils;
/**
* Http請求工具類
*
* @author 大漠知秋
*/
public class HttpRequestUtils {
/** 全局連接池對象 */
private static final PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager();
/**
* 靜態(tài)代碼塊配置連接池信息
*/
static {
// 設置最大連接數(shù)
connManager.setMaxTotal(200);
// 設置每個連接的路由數(shù)
connManager.setDefaultMaxPerRoute(20);
}
/**
* 獲取Http客戶端連接對象
*
* @param timeOut 超時時間
* @return Http客戶端連接對象
*/
public static CloseableHttpClient getHttpClient(Integer timeOut) {
// 創(chuàng)建Http請求配置參數(shù)
RequestConfig requestConfig = RequestConfig.custom()
// 獲取連接超時時間
.setConnectionRequestTimeout(timeOut)
// 請求超時時間
.setConnectTimeout(timeOut)
// 響應超時時間
.setSocketTimeout(timeOut)
.build();
/**
* 測出超時重試機制為了防止超時不生效而設置
* 如果直接放回false,不重試
* 這里會根據(jù)情況進行判斷是否重試
*/
HttpRequestRetryHandler retry = new HttpRequestRetryHandler() {
@Override
public boolean retryRequest(IOException exception, int executionCount, HttpContext context) {
if (executionCount >= 3) {// 如果已經(jīng)重試了3次隅居,就放棄
return false;
}
if (exception instanceof NoHttpResponseException) {// 如果服務器丟掉了連接胎源,那么就重試
return true;
}
if (exception instanceof SSLHandshakeException) {// 不要重試SSL握手異常
return false;
}
if (exception instanceof InterruptedIOException) {// 超時
return true;
}
if (exception instanceof UnknownHostException) {// 目標服務器不可達
return false;
}
if (exception instanceof ConnectTimeoutException) {// 連接被拒絕
return false;
}
if (exception instanceof SSLException) {// ssl握手異常
return false;
}
HttpClientContext clientContext = HttpClientContext.adapt(context);
HttpRequest request = clientContext.getRequest();
// 如果請求是冪等的,就再次嘗試
if (!(request instanceof HttpEntityEnclosingRequest)) {
return true;
}
return false;
}
};
// 創(chuàng)建httpClient
return HttpClients.custom()
// 把請求相關(guān)的超時信息設置到連接客戶端
.setDefaultRequestConfig(requestConfig)
// 把請求重試設置到連接客戶端
.setRetryHandler(retry)
// 配置連接池管理對象
.setConnectionManager(connManager)
.build();
}
/**
* GET請求
*
* @param url 請求地址
* @param timeOut 超時時間
* @return
*/
public static String httpGet(String url, Integer timeOut) {
String msg = "-1";
// 獲取客戶端連接對象
CloseableHttpClient httpClient = getHttpClient(timeOut);
// 創(chuàng)建GET請求對象
HttpGet httpGet = new HttpGet(url);
CloseableHttpResponse response = null;
try {
// 執(zhí)行請求
response = httpClient.execute(httpGet);
// 獲取響應實體
HttpEntity entity = response.getEntity();
// 獲取響應信息
msg = EntityUtils.toString(entity, "UTF-8");
} catch (ClientProtocolException e) {
System.err.println("協(xié)議錯誤");
e.printStackTrace();
} catch (ParseException e) {
System.err.println("解析錯誤");
e.printStackTrace();
} catch (IOException e) {
System.err.println("IO錯誤");
e.printStackTrace();
} finally {
if (null != response) {
try {
EntityUtils.consume(response.getEntity());
response.close();
} catch (IOException e) {
System.err.println("釋放鏈接錯誤");
e.printStackTrace();
}
}
}
return msg;
}
public static void main(String[] args) {
System.out.println(httpGet("http://www.baidu.com", 6000));
}
}
本節(jié)完畢,下一節(jié)記錄【安全的SSL/TLS連接-繞過證書】