httpclient源码阅读

httpclient功能十分丰富,虽然我们一般使用的是它最基本的功能。本文就说两方面,一是http调用流程,就是基本的功能,二是连接池的管理。

一 http调用流程

PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();

// 将最大连接数
cm.setMaxTotal(maxTotal);
// 每个路由基础的连接
cm.setDefaultMaxPerRoute(defaultMaxPerRoute);
// 默认设置
RequestConfig requestConfig = RequestConfig.custom()

.setSocketTimeout(defaultSocketTimeout).setConnectTimeout(defaultConnectTimeout)
        .setConnectionRequestTimeout(defaultConnectionRequestTimeout).build();
//创建httpclient
CloseableHttpClient  defaultClient = (HttpClients.custom().setDefaultRequestConfig(requestConfig).setConnectionManager(cm)
        .setSSLSocketFactory(createSSL()).build());

1,HttpClientBuilder创建httpclient

在HttpClientBuilder中,有很多准备操作,比如准备连接池、代理策略、重试策略、认证策略、长连接策略,这些我们暂时不细看。这里生成的httpclient是InternalHttpClient

2, httpClient.execute

此处调用逻辑是InternalHttpClient》MainClientExec》HttpRequestExecutor。在MainClientExec中向连接池租用连接。得到socket连接后执行请求。

protected HttpResponse doSendRequest(HttpRequest request, HttpClientConnection conn, HttpContext context) throws IOException, HttpException {
    Args.notNull(request, "HTTP request");
    Args.notNull(conn, "Client connection");
    Args.notNull(context, "HTTP context");
    HttpResponse response = null;
    context.setAttribute("http.connection", conn);
    context.setAttribute("http.request_sent", Boolean.FALSE);
   //sengheader
    conn.sendRequestHeader(request);
    if(request instanceof HttpEntityEnclosingRequest) {
        boolean sendentity = true;
        ProtocolVersion ver = request.getRequestLine().getProtocolVersion();
        if(((HttpEntityEnclosingRequest)request).expectContinue() && !ver.lessEquals(HttpVersion.HTTP_1_0)) {
            conn.flush();
            if(conn.isResponseAvailable(this.waitForContinue)) {
                response = conn.receiveResponseHeader();
                if(this.canResponseHaveBody(request, response)) {
                    conn.receiveResponseEntity(response);
                }

                int status = response.getStatusLine().getStatusCode();
                if(status < 200) {
                    if(status != 100) {
                        throw new ProtocolException("Unexpected response: " + response.getStatusLine());
                    }

                    response = null;
                } else {
                    sendentity = false;
                }
            }
        }

        if(sendentity) {
            conn.sendRequestEntity((HttpEntityEnclosingRequest)request);
        }
    }

    conn.flush();
    context.setAttribute("http.request_sent", Boolean.TRUE);
    return response;
}

二 连接池的管理

我们在发起http请求时,是如何向连接池租用连接的呢?

1,在PoolingHttpClientConnectionManager中有一个CPool。缓存的连接是在他的父类AbstractConnPool中管理的。

2,当向连接池申请时,连接池会根据域名route来判断是否已存在soctket连接,如何来判断呢,就是AbstractConnPool中的Map  routeToPool. 根据这个map,获取到一个RouteSpecificPool。这个池子中缓存的是同一个路由的socket连接。缓存多少个就是我们一开始设置的setDefaultMaxPerRoute。

private final Lock lock;
private final Condition condition;
private final ConnFactory<T, C> connFactory;
private final Map<T, RouteSpecificPool<T, C, E>> routeToPool;
private final Set<E> leased;
private final LinkedList<E> available;
private final LinkedList<Future<E>> pending;
private final Map<T, Integer> maxPerRoute;
private volatile boolean isShutDown;
private volatile int defaultMaxPerRoute;
private volatile int maxTotal;
private volatile int validateAfterInactivity;

3,如果RouteSpecificPool存在,则向其内部租赁。有三个集合,租用的逻辑就围绕其展开。等待的,是指,当连接不够用了,而缓存的个数已达上限,则等待,到了一定的时间还没有拿到,就放弃了。

private final T route;
//使用中的
private final Set<E> leased;
//空闲的
private final LinkedList<E> available;
//等待的
private final LinkedList<Future<E>> pending;

4,拿到连接CPoolEntry后,会校验起是否有效,如果校验不通过,则销毁,重新获取。

if(AbstractConnPool.this.validateAfterInactivity <= 0 || ex.getUpdated() + (long)AbstractConnPool.this.validateAfterInactivity > System.currentTimeMillis() || AbstractConnPool.this.validate(ex)) {
    this.entry = ex;
    this.done = true;
    AbstractConnPool.this.onLease(this.entry);
    if(callback != null) {
        callback.completed(this.entry);
    }

    PoolEntry var10000 = this.entry;
    return var10000;
}

转载于:https://my.oschina.net/u/3300636/blog/867775

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Apache HttpClient 是一个开源的、高性能的、易于使用的 HTTP 客户端库,广泛应用于 Java 应用程序中。下面简单介绍一下 HttpClient源码解析: 1. HttpClient 的主要类 HttpClient 的核心类是 CloseableHttpClientHttpClientBuilder。HttpClientBuilder 负责创建 CloseableHttpClient 实例,而 CloseableHttpClient 则封装了所有的 HTTP 请求和响应处理逻辑。 2. HttpClient 的请求发送流程 HttpClient 的请求发送流程包括以下几个步骤: - 创建 HttpClient 实例和 HttpUriRequest 实例; - 设置请求头和请求体; - 执行请求,并获取 HttpResponse 实例; - 解析响应,并将响应内容转换为所需的数据类型。 3. HttpClient 的连接管理 HttpClient 连接管理的核心是连接池,通过连接池可以提高 HTTP 请求的性能和效率。HttpClient 提供了 ConnectionReuseStrategy 接口和 ConnectionKeepAliveStrategy 接口,用于连接复用和连接保持的策略。 4. HttpClient 的认证和授权 HttpClient 提供了多种认证和授权方式,包括基本认证、摘要认证、NTLM 认证、OAuth 2.0、Bearer Token 等。 5. HttpClient 的异常处理 HttpClient 的异常处理包括两个方面:网络异常和 HTTP 异常。网络异常包括网络超时、连接中断等,HTTP 异常包括 4xx 和 5xx 状态码等。HttpClient 提供了相应的异常类和异常处理机制,方便开发者进行异常处理。 以上是 HttpClient 的简单源码解析,希望对你有所帮助。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值