文档章节

httpclient源码阅读

源135
 源135
发布于 2017/03/26 10:42
字数 657
阅读 72
收藏 0

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;
}

© 著作权归作者所有

源135
粉丝 0
博文 6
码字总数 2362
作品 0
私信 提问
Android:HttpClient研究

HttpClient4 用法 由HttpClient3 升级到 HttpClient_4 必看 摘要:HttpClient程序包是一个实现了 HTTP 协议的客户端编程工具包,要想熟练的掌握它,必须熟悉HTTP协议。一个最简单的调用如下:...

boonya
2015/03/27
141
2
HttpClient4.x:Get和Post提交数据

HttpClient是一款用Java写的非常好用的基于Http协议的客户端编程工具包。具体举例来讲,用它可以模拟form表单提交数据动作,可以模拟访问网页动作及得到网页源码内容等等,这两点或许是我们在...

liangtee
2012/12/02
9.5K
0
HttpClient在多线程环境下踩坑总结

HttpClient在多线程环境下踩坑总结 问题现场 在多线程环境下使用HttpClient组件对某个HTTP服务发起请求,运行一段时间之后发现客户端主机CPU利用率呈现出下降趋势,而不是一个稳定的状态。 ...

优惠券发放
03/28
0
0
WebMagic爬虫实现登陆状态保存

由于WebMagic的网络请求是通过Apache HttpClient请求,只需要拿到该对象进行登陆处理,后续的请求再使用同一个HttpClient对象请求,即可实现登陆状态下的请求,登陆相关的cookies不需要自己进...

0x5f3759df
2018/12/23
379
0
关于webmagic源码和HttpClient4.3的几个疑问

@黄亿华 前辈,你好,最近又开始重新研读webmagic的源码,但是遇到了几个问题。自己也非常详细认真地阅读了HttpClient的英文Manual,但是不明白,想跟你请教一下: 1,问题同样来自于HttpCli...

Timco
2014/03/13
2.4K
7

没有更多内容

加载失败,请刷新页面

加载更多

可能是国内第一篇全面解读 Java 现状及趋势的文章

作者 | 张晓楠 Dragonwell JDK 最新版本 8.1.1-GA 发布,包括全新特性和更新! 导读:InfoQ 发布《2019 中国 Java 发展趋势报告》,反映 Java 在中国发展的独特性,同时也希望大家对 Java 有...

阿里云官方博客
27分钟前
6
0
Spring Boot 2.x基础教程:Swagger静态文档的生成

前言 通过之前的两篇关于Swagger入门以及具体使用细节的介绍之后,我们已经能够轻松地为Spring MVC的Web项目自动构建出API文档了。如果您还不熟悉这块,可以先阅读: Spring Boot 2.x基础教程...

程序猿DD
31分钟前
4
0
《毅力》读书笔记

1.确信你全身心地投入 2.准备好为目标进行艰难的跋涉 3.通过减少需要使用毅力的情形,为将来的挑战做好准备 4.尽可能具体细致地确定你的目标和实现目标的过程 5.把挑战分解为小而易于管理的小...

lingch
32分钟前
3
0
zk中快速选举FastLeaderElection实现

选举涉及概念 服务器状态 投票 如何选择投票? 协议 选举 如何进行选举? epoch 发送者 接收者 发送队列 接收队列 服务器状态 public enum ServerState { LOOKING,寻找Leader状态,当服务处于...

writeademo
35分钟前
4
0
教你玩转Linux—磁盘管理

Linux磁盘管理好坏直接关系到整个系统的性能问题,Linux磁盘管理常用三个命令为df、du和fdisk。 df df命令参数功能:检查文件系统的磁盘空间占用情况。可以利用该命令来获取硬盘被占用了多少...

Linux就该这么学
38分钟前
5
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部