異步請求CloseableHttpAsyncClient的使用


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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM