1、前言
項目有個需求,需要把一些沒用影響業務邏輯的http請求改成異步請求,httpclient在4.0后提供新的api CloseableHttpAsyncClient可以使用,記錄下使用過程。
2、網絡調用類型
(1)傳統BIO(Blocking IO)
同步阻塞式IO,服務器實現模式為一個連接一個線程,即客戶端有連接請求時服務器端就需要啟動一個線程進行處理,如果這個連接不做任何事情會造成不必要的線程開銷,當然可以通過線程池機制改善。
(2)NIO(Not-Blocking IO)
NIO:同步非阻塞式IO,服務器實現模式為一個請求一個線程,即客戶端發送的連接請求都會注冊到多路復用器上,多路復用器輪詢到連接有I/O請求時才啟動一個線程進行處理。
(3)AIO(NIO.2)
異步非阻塞式IO,服務器實現模式為一個有效請求一個線程,客戶端的I/O請求都是由OS先完成了再通知服務器應用去啟動線程進行處理。
3、CloseableHttpAsyncClient
CloseableHttpAsyncClient是apache在4.0后提供AIO操作的api,基本使用如下
1)pom.xml引用如下
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.2</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpcore</artifactId>
<version>4.4.5</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpcore-nio</artifactId>
<version>4.4.5</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpasyncclient</artifactId>
<version>4.1.2</version>
</dependency>
2)構造連接
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;
import org.apache.http.impl.nio.client.HttpAsyncClients;
import org.apache.http.impl.nio.conn.PoolingNHttpClientConnectionManager;
import org.apache.http.impl.nio.reactor.DefaultConnectingIOReactor;
import org.apache.http.impl.nio.reactor.IOReactorConfig;
import org.apache.http.nio.reactor.ConnectingIOReactor;
import org.apache.http.nio.reactor.IOReactorException;
/**
* @Title:
* @Description:異步連接
* @Author: yangyongzhen
* @Date: 2019/9/26 14:38
*/
public class AsynHttpClient {
private static CloseableHttpAsyncClient client = null;
public static CloseableHttpAsyncClient getHttpClient() {
if (client == null) {
synchronized (AsynHttpClient.class) {
if (client == null) {
RequestConfig requestConfig = RequestConfig.custom()
.setConnectTimeout(2000)//連接超時,連接建立時間,三次握手完成時間
.setSocketTimeout(2000)//請求超時,數據傳輸過程中數據包之間間隔的最大時間
.setConnectionRequestTimeout(20000)//使用連接池來管理連接,從連接池獲取連接的超時時間
.build();
//配置io線程
IOReactorConfig ioReactorConfig = IOReactorConfig.custom().
setIoThreadCount(Runtime.getRuntime().availableProcessors())
.setSoKeepAlive(true)
.build();
//設置連接池大小
ConnectingIOReactor ioReactor = null;
try {
ioReactor = new DefaultConnectingIOReactor(ioReactorConfig);
} catch (IOReactorException e) {
e.printStackTrace();
}
PoolingNHttpClientConnectionManager connManager = new PoolingNHttpClientConnectionManager(ioReactor);
connManager.setMaxTotal(5);//最大連接數設置1
connManager.setDefaultMaxPerRoute(5);//per route最大連接數設置
client = HttpAsyncClients.custom()
.setConnectionManager(connManager)
.setDefaultRequestConfig(requestConfig)
.build();
client.start();
}
}
}
return client;
}
public static HttpPost getPostBody(String urls, String bodys, ContentType contentType) {
HttpPost post = null;
StringEntity entity = null;
post = new HttpPost(urls);
entity = new StringEntity(bodys, contentType);
post.setEntity(entity);
return post;
}
}
幾個重要的參數
ConnectTimeout : 連接超時,連接建立時間,三次握手完成時間。
SocketTimeout : 請求超時,數據傳輸過程中數據包之間間隔的最大時間。
ConnectionRequestTimeout : 使用連接池來管理連接,從連接池獲取連接的超時時間。
ConnTotal:連接池中最大連接數;
ConnPerRoute(1000):分配給同一個route(路由)最大的並發連接數,route為運行環境機器到目標機器的一條線路
3)測試
CloseableHttpAsyncClient httpclient = HttpAsyncClients.createDefault();
CloseableHttpAsyncClient httpClient = AsynHttpClient.getHttpClient();
// String url = "http://www.baidu.com/";
// String url = "https://www.cnblogs.com/";
String url = "https://study.163.com/";
String stringBody = JSONObject.toJSONString(AlarmInfoFrm.getInstanceFrom(alarmInfo));
HttpPost postBody = AsynHttpClient.getPostBody(url, stringBody, ContentType.APPLICATION_JSON);
//回調
FutureCallback<HttpResponse> callback = new FutureCallback<HttpResponse>() {
@Override
public void completed(HttpResponse result) {
System.out.println(result.getStatusLine() + "----i:"+i++ );
}
@Override
public void failed(Exception e) {
e.printStackTrace();
System.err.println("失敗:");
}
@Override
public void cancelled() {
System.err.println("cancelled");
}
};
//連接池執行
httpClient.execute(postBody,callback);
參考的博客和官網地址如下
https://blog.csdn.net/ouyang111222/article/details/78884634
http://hc.apache.org/httpcomponents-asyncclient-4.1.x/quickstart.html