• 一、简介
  • 二、mvn依赖
  • 三、客户端
    • 3.1 官网实例
    • 3.2. 根据官方文档的介绍,简单封装了一个异步HttpClient工具类
    • 3.3 基本原理
  • 四、参考文档

一、简介

HttpClient提供了两种I/O模型:经典的java阻塞I/O模型和基于Java NIO的异步非阻塞事件驱动I/O模型。

Java中的阻塞I/O是一种高效、便捷的I/O模型,非常适合并发连接数量相对适中的高性能应用程序。只要并发连接的数量在1000个以下并且连接大多忙于传输数据,阻塞I/O模型就可以提供最佳的数据吞吐量性能。然而,对于连接大部分时间保持空闲的应用程序,上下文切换的开销可能会变得很大,这时非阻塞I/O模型可能会提供更好的替代方案。 异步I/O模型可能更适合于比较看重资源高效利用、系统可伸缩性、以及可以同时支持更多HTTP连接的场景。

二、mvn依赖

httpclient在4.x之后开始提供基于nio的异步版本httpasyncclient,httpasyncclient借助了Java并发库和nio进行封装(虽说NIO是同步非阻塞IO,但是HttpAsyncClient提供了回调的机制,与netty类似,所以可以模拟类似于AIO的效果),其调用方式非常便捷.

<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpasyncclient</artifactId>
<version>4.1.4</version>
</dependency>

三、客户端

 3.1 官网实例

CloseableHttpAsyncClient httpclient = HttpAsyncClients.createDefault();
try {
// Start the client
httpclient.start(); // Execute request
final HttpGet request1 = new HttpGet("http://www.apache.org/");
Future<HttpResponse> future = httpclient.execute(request1, null);
// and wait until a response is received
HttpResponse response1 = future.get();
System.out.println(request1.getRequestLine() + "->" + response1.getStatusLine()); // One most likely would want to use a callback for operation result
final CountDownLatch latch1 = new CountDownLatch(1);
final HttpGet request2 = new HttpGet("http://www.apache.org/");
httpclient.execute(request2, new FutureCallback<HttpResponse>() { public void completed(final HttpResponse response2) {
latch1.countDown();
System.out.println(request2.getRequestLine() + "->" + response2.getStatusLine());
} public void failed(final Exception ex) {
latch1.countDown();
System.out.println(request2.getRequestLine() + "->" + ex);
} public void cancelled() {
latch1.countDown();
System.out.println(request2.getRequestLine() + " cancelled");
} });
latch1.await(); // In real world one most likely would also want to stream
// request and response body content
final CountDownLatch latch2 = new CountDownLatch(1);
final HttpGet request3 = new HttpGet("http://www.apache.org/");
HttpAsyncRequestProducer producer3 = HttpAsyncMethods.create(request3);
AsyncCharConsumer<HttpResponse> consumer3 = new AsyncCharConsumer<HttpResponse>() { HttpResponse response; @Override
protected void onResponseReceived(final HttpResponse response) {
this.response = response;
} @Override
protected void onCharReceived(final CharBuffer buf, final IOControl ioctrl) throws IOException {
// Do something useful
} @Override
protected void releaseResources() {
} @Override
protected HttpResponse buildResult(final HttpContext context) {
return this.response;
} };
httpclient.execute(producer3, consumer3, new FutureCallback<HttpResponse>() { public void completed(final HttpResponse response3) {
latch2.countDown();
System.out.println(request3.getRequestLine() + "->" + response3.getStatusLine());
} public void failed(final Exception ex) {
latch2.countDown();
System.out.println(request3.getRequestLine() + "->" + ex);
} public void cancelled() {
latch2.countDown();
System.out.println(request3.getRequestLine() + " cancelled");
} });
latch2.await(); } finally {
httpclient.close();
}

3.2. 根据官方文档的介绍,简单封装了一个异步HttpClient工具类

public class AsyncHttpClientUtil {
private static final Logger logger = LoggerFactory.getLogger(AsyncHttpClientUtil.class);
//从池中获取链接超时时间(ms)
private static final int CONNECTION_REQUEST_TIMEOUT = 10000;
//建立链接超时时间(ms)
private static final int CONNECT_TIMEOUT = 10000;
//读取超时时间(ms)
private static final int SOCKET_TIMEOUT = 5000;
//连接数
private static final int MAX_TOTAL = 50;
private static final int MAX_PER_ROUTE = 50; private static final CloseableHttpAsyncClient httpclient;
private static PoolingNHttpClientConnectionManager poolManager; static {
httpclient=init();
httpclient.start();
} private static CloseableHttpAsyncClient init() {
CloseableHttpAsyncClient client=null;
try {
//配置io线程
IOReactorConfig ioReactorConfig = IOReactorConfig.custom().
setIoThreadCount(Runtime.getRuntime().availableProcessors())
.setSoKeepAlive(true)
.build();
//创建一个ioReactor
ConnectingIOReactor ioReactor = new DefaultConnectingIOReactor(ioReactorConfig);
// poolManager=new PoolingNHttpClientConnectionManager(new DefaultConnectingIOReactor());
poolManager=new PoolingNHttpClientConnectionManager(ioReactor);
//设置连接池大小
poolManager.setMaxTotal(MAX_TOTAL);
poolManager.setDefaultMaxPerRoute(MAX_PER_ROUTE);
// 配置请求的超时设置
RequestConfig requestConfig = RequestConfig.custom()
.setConnectionRequestTimeout(CONNECTION_REQUEST_TIMEOUT)
.setConnectTimeout(CONNECT_TIMEOUT)
.setSocketTimeout(SOCKET_TIMEOUT)
.build(); client= HttpAsyncClients.custom()
.setConnectionManager(poolManager)
.setDefaultRequestConfig(requestConfig)
.build();
return client;
} catch (IOReactorException e) {
e.printStackTrace();
}
return client;
} public static String get(String url, List<NameValuePair> ns) {
HttpGet httpget;
URIBuilder uri = new URIBuilder();
try {
if (ns!=null){
uri.setPath(url);
uri.addParameters(ns);
httpget = new HttpGet(uri.build());
}else{
httpget = new HttpGet(url);
} // One most likely would want to use a callback for operation result
httpclient.execute(httpget, new FutureCallback<HttpResponse>() { public void completed(final HttpResponse response) {
System.out.println(httpget.getRequestLine() + "->" + response.getStatusLine());
try {
System.out.println("当前请求状态:"+poolManager.getTotalStats()+", response="+EntityUtils.toString(response.getEntity()));
} catch (IOException e) {
e.printStackTrace();
}
} public void failed(final Exception ex) {
System.out.println(httpget.getRequestLine() + "->" + ex);
} public void cancelled() {
System.out.println(httpget.getRequestLine() + " cancelled");
} }); }catch (Exception e){
logger.error("[发送get请求失败]URL:{},异常:",uri.getUserInfo(), e);
}
return null;
} public static void main(String[] args) {
for (int i=0; i<10;i++){
System.out.println("第" + i +"次:");
get("http://httpbin.org/get",null);
}
}
}

3.3 基本原理

HTTPAysncClient 最后使用的是 InternalHttpAsyncClient,在 InternalHttpAsyncClient 中有个 ConnectionManager,这个就是我们管理连接的管理器。

而在 httpAsync 中只有一个实现那就是 PoolingNHttpClientConnectionManager。这个连接管理器中有两个我们比较关心的,一个是 Reactor,一个是 Cpool:

  • Reactor:所有的 Reactor 这里都是实现了 IOReactor 接口。在 PoolingNHttpClientConnectionManager 中会有拥有一个 Reactor,那就是 DefaultConnectingIOReactor,这个 DefaultConnectingIOReactor,负责处理 Acceptor。

在 DefaultConnectingIOReactor 有个 excutor 方法,生成 IOReactor 也就是我们图中的 BaseIOReactor,进行 IO 的操作。

  • CPool:在 PoolingNHttpClientConnectionManager 中有个 CPool,主要是负责控制我们连接,我们上面所说的 maxTotal 和 defaultMaxPerRoute,都是由其进行控制。

如果每个路由有满了,它会断开最老的一个链接;如果总共的 total 满了,它会放入 leased 队列,释放空间的时候就会将其重新连接。

关于Reactor可参考: https://www.cnblogs.com/doit8791/p/7461479.html

四、参考文档

  1. http://hc.apache.org/httpcomponents-asyncclient-4.1.x/index.html
  2. http://hc.apache.org/httpcomponents-asyncclient-4.1.x/httpasyncclient/xref/index.html
  3. http://ifeve.com/httpclient-async-call/
  4. https://blog.csdn.net/ouyang111222/article/details/78884634

异步httpClient(Async HttpClient)的更多相关文章

  1. MVC+Spring.NET+NHibernate .NET SSH框架整合 C# 委托异步 和 async /await 两种实现的异步 如何消除点击按钮时周围出现的白线? Linq中 AsQueryable(), AsEnumerable()和ToList()的区别和用法

    MVC+Spring.NET+NHibernate .NET SSH框架整合   在JAVA中,SSH框架可谓是无人不晓,就和.NET中的MVC框架一样普及.作为一个初学者,可以感受到.NET出了MV ...

  2. C#异步编程----async和await组合的写法

    微软示例: private async void StartButton_Click(object sender, RoutedEventArgs e) { // ExampleMethodAsync ...

  3. 抓住异步编程async/await语法糖的牛鼻子: SynchronizationContext

    长话短说,本文带大家抓住异步编程async/await语法糖的牛鼻子: SynchronizationContext 引言 C#异步编程语法糖async/await,使开发者很容易就能编写异步代码. ...

  4. 温故知新,CSharp遇见异步编程(Async/Await),聊聊异步编程最佳做法

    什么是异步编程(Async/Await) Async/Await本质上是通过编译器实现的语法糖,它让我们能够轻松的写出简洁.易懂.易维护的异步代码. Async/Await是C# 5引入的关键字,用以 ...

  5. 如何避免让线程摸鱼,请用异步技术 async await 拿捏他~

    发现问题 你点了外卖后,会一直不做其它事情,一直等外卖的到来么? 当然不会拉! 我们来看看代码世界的: public void Query(){ // 当前线程 向 数据库服务器 发起查询命令 // ...

  6. 新旧apache HttpClient 获取httpClient方法

    在apache httpclient 4.3版本中对很多旧的类进行了deprecated标注,通常比较常用的就是下面两个类了. DefaultHttpClient -> CloseableHtt ...

  7. 异步编程Async/await关键字

    异步编程Async \await 关键字在各编程语言中的发展(出现)纪实. 时间 语言版本 2012.08.15 C#5.0(VS2012) 2015.09.13 Python 3.5 2016.03 ...

  8. spring boot / cloud (四) 自定义线程池以及异步处理@Async

    spring boot / cloud (四) 自定义线程池以及异步处理@Async 前言 什么是线程池? 线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务.线 ...

  9. C++笔记-并发编程 异步任务(async)

    转自 https://www.cnblogs.com/diysoul/p/5937075.html 参考:https://zh.cppreference.com/w/cpp/thread/lock_g ...

  10. c#中@标志的作用 C#通过序列化实现深表复制 细说并发编程-TPL 大数据量下DataTable To List效率对比 【转载】C#工具类:实现文件操作File的工具类 异步多线程 Async .net 多线程 Thread ThreadPool Task .Net 反射学习

    c#中@标志的作用   参考微软官方文档-特殊字符@,地址 https://docs.microsoft.com/zh-cn/dotnet/csharp/language-reference/toke ...

随机推荐

  1. ElasticSearch之cat allocation API

    查看各节点上各个shard的硬件使用情况,命令样例如下: curl -X GET "https://localhost:9200/_cat/allocation?v=true&pre ...

  2. 一款便捷操作移动端设备的PC工具

    说明 该项目基于[Tinyui]框架开发.为电脑端(Windows/MacOS/Linux)操作移动设备提供便捷操作的工具. 项目代码已开源:☞ Github ☜ ☞ Gitee ☜ 功能 运行 由于 ...

  3. 文心一言 VS 讯飞星火 VS chatgpt (45)-- 算法导论6.1 3题

    三.证明:在最大堆的任一子树中,该子树所包含的最大元素在该子树的根结点上. 文心一言: 在最大堆中,根结点是整个堆中最大元素的孩子,因此它包含的最大元素是在该子树的根结点上. 我们可以通过递归的方式证 ...

  4. Spark Streaming快速入门

    Spark Streaming快速入门 一.简介 Spark Streaming 是构建在 Spark Core 基础之上的流处理框架(但实际上是微批次处理框架),是 Spark 非常重要的组成部分. ...

  5. MySQL篇:第六章_详解mysql视图

    周末有朋友来上海没来得及更新,特此更两篇以正身 视图 含义:理解成一张虚拟的表 视图和表的区别: 使用方式 占用物理空间 视图 完全相同 不占用,仅仅保存的是sql逻辑 表 完全相同 占用 视图的好处 ...

  6. 第九部分_Shell脚本之case语句

    case语句 关键词:确认过眼神,你是对的人 case语句为多重匹配语句 如果匹配成功,执行相匹配的命令 1. 语法结构 说明:pattern表示需要匹配的模式 case var in #定义变量;v ...

  7. 华为云发布CodeArts Req需求管理工具,让需求管理化繁为简

    摘要:华为云正式发布CodeArts Req,这是一款自主研发的软件研发管理与团队协作工具,旨在助力企业大规模研发转型成功,释放组织生产力. 本文分享自华为云社区<华为云发布CodeArts R ...

  8. 华为云GaussDB专家走进课堂,跟莘莘学子聊聊数据库

    摘要:华为云GaussDB走进北邮,技术专家走进课堂带来数据库前沿资讯. 近期,各地疫情又一次席卷而来,居家隔离成为常态.不过,外出的不便并没有阻挡莘莘学子求知的渴望,线上课堂成为了大多学生上课的主要 ...

  9. 云图说|玩转华为HiLens之端云协同AI开发

    阅识风云是华为云信息大咖,擅长将复杂信息多元化呈现,其出品的一张图(云图说).深入浅出的博文(云小课)或短视频(云视厅)总有一款能让您快速上手华为云.更多精彩内容请单击此处. 摘要: 华为HiLens ...

  10. 火山引擎A/B测试在消费行业的案例实践

    更多技术交流.求职机会,欢迎关注字节跳动数据平台微信公众号,回复[1]进入官方交流群 近日,火山引擎数智平台举办了"走进火山-全链路增长:数据飞轮转动消费新生力"的活动,其中火山引 ...