异步请求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

原文地址:https://www.cnblogs.com/yz-yang/p/11596844.html