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