Httpclient4.5详解之源码解析和使用一: 关键执行流程源码解读

本文深入解析HttpClient4.5的源码,关注关键执行流程和连接池的使用。通过HttpClients.createDefault()创建HttpClient对象,深入到InternalHttpClient的doExecute方法,了解RetryExec和RedirectExec的工作原理,以及HttpConnection如何处理请求和响应。文章揭示了HttpClient如何通过连接池管理Socket,为后续的源码分析埋下伏笔。
摘要由CSDN通过智能技术生成

前言

作为一个java后端开发,调用http协议的请求一直使用的httpclient,但是对他内部原理却一概不知,由于它使用了连接池来解决连接资源消耗所带来的问题,同时我们在使用时他也隐匿了连接池操作的很多细节,所以若是使用不当势必会带来很多隐藏的坑(诸如CLOSE_WAIT过多造成服务假死之类)所以最近有时间看了他内部源码,特此记录下来。

httpclient当前版本总览:

httpclient是apache下的一个子项目,commons-httpclient是最老的版本,现在官方已经不再开发和维护同时也不被建议使用,已经是一个遗留项目,取而代之的是httpclientcommons项目。目前httpclientcommons项目最新的release版本为4.5.9, 5.0的beta版本也已经发布。而httpclient3.x 4.x和4,.3之后的版本之前的API也是有所不同。

源码解读

先看一点httpclientcommons官方使用示例代码

CloseableHttpClient httpclient = HttpClients.createDefault();
HttpGet httpGet = new HttpGet("http://targethost/homepage");
CloseableHttpResponse response1 = httpclient.execute(httpGet);
// The underlying HTTP connection is still held by the response object
// to allow the response content to be streamed directly from the network socket.
// In order to ensure correct deallocation of system resources
// the user MUST call CloseableHttpResponse#close() from a finally clause.
// Please note that if response content is not fully consumed the underlying
// connection cannot be safely re-used and will be shut down and discarded
// by the connection manager. 
try {
    System.out.println(response1.getStatusLine());
    HttpEntity entity1 = response1.getEntity();
    // do something useful with the response body
    // and ensure it is fully consumed
    EntityUtils.consume(entity1);
} finally {
    response1.close();
}

HttpPost httpPost = new HttpPost("http://targethost/login");
List <NameValuePair> nvps = new ArrayList <NameValuePair>();
nvps.add(new BasicNameValuePair("username", "vip"));
nvps.add(new BasicNameValuePair("password", "secret"));
httpPost.setEntity(new UrlEncodedFormEntity(nvps));
CloseableHttpResponse response2 = httpclient.execute(httpPost);

try {
    System.out.println(response2.getStatusLine());
    HttpEntity entity2 = response2.getEntity();
    // do something useful with the response body
    // and ensure it is fully consumed
    EntityUtils.consume(entity2);
} finally {
    response2.close();
}

使用示例中关键代码中是使用HttpClients.createDefault()创建了一个CloseableHttpClient对象(线程安全对象,可共享),接下来就去看看HttpClients.createDefault()方法。

 /**
     * Creates {@link CloseableHttpClient} instance with default
     * configuration.
     */
    public static CloseableHttpClient createDefault() {
        return HttpClientBuilder.create().build();
    }

通过HttpClientBuilder#build返回一个CloseableHttpClient对象,接下来看下HttpClientBuilder#build,此方法篇幅较长,只看关键代码即可,并不影响对我们引用层面的理解。

public CloseableHttpClient build() {
        // Create main request executor
        // We copy the instance fields to avoid changing them, and rename to avoid accidental use of the wrong version
        PublicSuffixMatcher publicSuffixMatcherCopy = this.publicSuffixMatcher;
        if (publicSuffixMatcherCopy == null) {
            publicSuffixMatcherCopy = PublicSuffixMatcherLoader.getDefault();
        }
        //HttpRequestExecutor通过preProcess,execute,postProcess方法拦截请求,发送请求,接收        
        //请求,这个后面会再次看到这个对象的使用
        HttpRequestExecutor requestExecCopy = this.requestExec;
        if (requestExecCopy == null) {
            requestExecCopy = new HttpRequestExecutor();
        }
        //初始化连接池对象,若是应用层不初始化一个则会默认初始化一个默认defaultMaxPerRoute=2,        
        //maxTotal=20 ValidateAfterInactivity=2000(从池中获取连接时校验连接是否可用的间隔时            
        //间), validityDeadline = Long.MAX_VALUE,this.expiry = this.validityDeadline;
        //连接最终失效时间和连接过期时间都是Long.MAX_VALUE,具体后面分析httplcientConnection 
        //如何从连接池获取时会查看HttpClientConnectionManager的构造方法
        HttpClientConnectionManager connManagerCopy = this.connManager;
        if (connManagerCopy == null) {
            LayeredConnectionSocketFactory sslSocketFactoryCopy = this.sslSocketFactory;
            if (sslSocketFactoryCopy == null) {
                final String[] supportedProtocols = systemProperties ? split(
                        System.getProperty("https.protocols")) : null;
                final String[] supportedCipherSuites = systemProperties ? split(
                        System.getProperty("https.cipherSuites")) : null;
                HostnameVerifier hostnameVerifierCopy = this.hostnameVerifier;
                if (hostnameVerifierCopy == null) {
                    hostnameVerifierCopy = new DefaultHostnameVerifier(publicSuffixMatcherCopy);
                }
                if (sslContext != null) {
                    sslSocketFactoryCopy = new SSLConnectionSocketFactory(
                            sslContext, supportedProtocols, supportedCipherSuites, hostnameVerifierCopy);
                } else {
                    if (systemProperties) {
                        sslSocketFactoryCopy = new SSLConnectionSocketFactory(
                                (SSLSocketFactory) SSLSocketFactory.getDefault(),
                                supportedProtocols, supportedCipherSuites, hostnameVerifierCopy);
                    } else {
                        sslSocketFactoryCopy = new SSLConnectionSocketFactory(
                                SSLContexts.createDefault(),
                                hostnameVerifierCopy);
                    }
                }
            }
            @SuppressWarnings("resource")
            final PoolingHttpClientConnection
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值