Apache Httpclient5 异步Http Client 源码分析

前言

Apache HttpAsyncClient 源码分析 前文分析过异步http client的实现。
近日,org.apache.httpcomponents 发布了 http cleint 5,一个项目囊括了过去多个http client,其中就包括HttpAsyncClient 。
http cleint 5的具体实现与旧版类似,详见前文。
本文主要分析异步client的各个配置的含义。

  • 依赖

    
    
        org.apache.httpcomponents.client5
        httpclient5
        5.1
    

  • 样例代码
    http-client-5-demo

正文

全部配置

IOReactorConfig ioReactorConfig = IOReactorConfig.custom()
        .setSoTimeout(Timeout.ofMilliseconds(250))          // 1.1
        .setSelectInterval(TimeValue.ofMilliseconds(50))    // 1.2
        .build();

PoolingAsyncClientConnectionManager build = PoolingAsyncClientConnectionManagerBuilder.create()
        .setPoolConcurrencyPolicy(PoolConcurrencyPolicy.LAX)  // 2.1
        .setMaxConnPerRoute(6).build();                       // 2.2

Main.client = HttpAsyncClients.custom()
        .setIOReactorConfig(ioReactorConfig)
        .setConnectionManager(build)
        .disableAutomaticRetries()       // 3.1
        .build();

client.start();

SimpleHttpRequest httpRequest = SimpleHttpRequest.create(Method.GET.name(), "http://127.0.0.1:8080/greeting");
final SimpleHttpRequest request = SimpleRequestBuilder.copy(httpRequest)
        .addParameter("name", "124")
        .build();
RequestConfig config = RequestConfig.copy(RequestConfig.DEFAULT)
        .setConnectTimeout(150, TimeUnit.MILLISECONDS)              // 4.1 
        .setConnectionRequestTimeout(200, TimeUnit.MILLISECONDS)    // 4.2
        .setResponseTimeout(100, TimeUnit.MILLISECONDS).build();    // 4.3
request.setConfig(config);

final Future future = client.execute(
        SimpleRequestProducer.create(request),
        SimpleResponseConsumer.create(),
        new FutureCallback() {

            @Override
            public void completed(final SimpleHttpResponse response) {
                System.out.println(request + "->" + new StatusLine(response));
                System.out.println(response.getBody());
            }

            @Override
            public void failed(final Exception ex) {
                System.out.println(request + "->" + ex);
            }

            @Override
            public void cancelled() {
                System.out.println(request + " cancelled");
            }

        });

大致结构

  1. 我们通过CloseableHttpAsyncClient接口使用http client,它的实现类是 InternalHttpAsyncClient
    1.1 http client的ioReactor字段使用的是DefaultConnectingIOReactor类。
    DefaultConnectingIOReactor类有两个字段
    private final SingleCoreIOReactor[] workers;
    private final MultiCoreIOReactor ioReactor;

构造函数中 ioReactor 由 workers 和 执行worker的线程构造。

this.workers[i] = dispatcher;
threads[i] = (threadFactory != null ? threadFactory : THREAD_FACTORY).newThread(new IOReactorWorker(dispatcher));
this.ioReactor = new MultiCoreIOReactor(this.workers, threads);

MultiCoreIOReactor ioReactor 中没有什么重要代码,就是在统一管理SingleCoreIOReactor[] workers
SingleCoreIOReactor类中的主要方法为SingleCoreIOReactor#doExecute,负责selector.select(),然后处理事件。

具体分析

  1. IOReactorConfig
    1.1 soTimeout
    相当于4.3的默认值。如果设置4.3,则使用此timeout;如果设置了4.3,则最终4.3的值生效
    1.2 selectInterval
    设置select的间隔
    用于SingleCoreIOReactor.doExecute()方法内的
    final int readyCount = this.selector.select(this.selectTimeoutMillis);selectTimeoutMillis
    影响select的频率,也会影响timeout的最小精度。
    如 设置为 100ms,那么超时中的50ms会被忽略。

  2. PoolingAsyncClientConnectionManager
    2.1 poolConcurrencyPolicy
    STRICT 模式通过加锁的方式对2.2严格计数; LAX 通过cas的方式宽松计数
    设置STRICT,会使用StrictConnPool实现类;
    设置LAX ,会使用LaxConnPool实现类。

2.2 maxConnPerRoute
每个route最多能有多少个connection,具体可见前言中提到的Apache HttpAsyncClient 源码分析一文。
在2.1中的ConnPool实现类的lease()方法中会被使用

  1. HttpAsyncClients
    3.1 automaticRetriesDisabled
    关闭自动重试

  2. RequestConfig
    4.1 connectTimeout
    建立tcp连接的超时
    会被SingleCoreIOReactor.connect()中用到,用于创建IOSessionRequest
    进而在InternalConnectChannel.onIOEvent()方法中检查超时。

4.2 connectionRequestTimeout
从ManagedConnPool (STRICT or LAX)中lease connection。
如果达到maxConnPerRoute,需要在队列中等待的超时时间
4.3 responseTimeout
获取 http respones 的timeout
最后会被赋值到IOSessionImpl类的socketTimeout字段。
在抽象类InternalChannel.checkTimeout方法中被使用,(实现类是InternalDataChannel)。
selector.select()后,会检查一下所有的SelectionKey.attachment,即InternalChannel的超时。
所以1.2设置的selectInterval值,会影响此超时的精度。

你可能感兴趣的:(Apache Httpclient5 异步Http Client 源码分析)