HttpClient4.3 连接池

连接池管理器一般使用PoolingHttpClientConnectionManager,它管理着连接池,可以同时为很多线程提供http连接请求。Connections are pooled on a per route basis.当请求一个新的连接时,如果连接池有有可用的持久连接,连接管理器就会使用其中的一个,而不是再创建一个新的连接。PoolingHttpClientConnectionManager维护的连接数在每个路由基础和总数上都有限制。默认,每个路由基础上的连接不超过2个,总连接数不能超过20。在实际应用中,这个限制可能会太小了,尤其是当服务器也使用Http协议时。

多线程请求执行

当使用了请求连接池管理器(比如PoolingClientConnectionManager)后,HttpClient就可以同时执行多个线程的请求了。PoolingClientConnectionManager会根据它的配置来分配请求连接。如果连接池中的所有连接都被占用了,那么后续的请求就会被阻塞,直到有连接被释放回连接池中。为了防止永远阻塞的情况发生,我们可以把http.conn-manager.timeout的值设置成一个整数。如果在超时时间内,没有可用连接,就会抛出ConnectionPoolTimeoutException异常。

HttpClient的实例是线程安全的,可以被多个线程共享访问,但是仍旧推荐每个线程都要有自己专用实例的HttpContext。

官方示例

PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
    // 将最大连接数增加到200
    cm.setMaxTotal(200);
    // 将每个路由基础的连接增加到20
    cm.setDefaultMaxPerRoute(20);
    //将目标主机的最大连接数增加到50
    HttpHost localhost = new HttpHost("www.yeetrack.com", 80);
    cm.setMaxPerRoute(new HttpRoute(localhost), 50);

    CloseableHttpClient httpClient = HttpClients.custom()
            .setConnectionManager(cm)
            .build();


在自己项目中也用到了连接池管理器,处理了普通的http请求与忽略https证书。这货很灵活,代码仅供参考,毕竟只是为了方便项目。

import java.security.GeneralSecurityException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.concurrent.TimeUnit;

import javax.net.ssl.SSLContext;

import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.ssl.TrustStrategy;

/**
 * HttpClient连接池<br/>
 * Author:杨杰超<br/>
 * Date:2018年3月12日 下午3:08:19 <br/>
 * Copyright (c) 2018, yangjiechao@dingtalk.com All Rights Reserved.<br/>
 *
 */
public class GlobalHttpClientConnectionManager {

    // 设置访问协议
    private PoolingHttpClientConnectionManager connMrg = null;

    // 超时参数
    private long timeToLive = 10;
    // 超时参数单位
    private TimeUnit tunit = TimeUnit.SECONDS;
    // 设置整个连接池最大连接数
    private int maxTotal = 256;
    // 单个路由最大连接数
    private int defaultMaxPerRoute = 64;

    /**
     * 初始化
     */
    public GlobalHttpClientConnectionManager() {
        connMrg = new PoolingHttpClientConnectionManager(timeToLive, tunit);
        connMrg.setMaxTotal(maxTotal);
        connMrg.setDefaultMaxPerRoute(defaultMaxPerRoute);
    }

    /**
     * 初始化
     * 
     * @param timeToLive
     *            超时参数
     * @param tunit
     *            超时单位
     * @param maxTotal
     *            连接池最大连接数
     * @param defaultMaxPerRoute
     *            主机对MaxTotal的一个细分,比如:MaxtTotal=256
     *            DefaultMaxPerRoute=64,而我只连接到http://www.baidu.com时,
     *            到这个主机的并发最多只有64而不是128
     */
    public GlobalHttpClientConnectionManager(long timeToLive, TimeUnit tunit, int maxTotal, int defaultMaxPerRoute) {
        this.timeToLive = timeToLive;
        this.tunit = tunit;
        this.maxTotal = maxTotal;
        this.defaultMaxPerRoute = defaultMaxPerRoute;
    }

    public PoolingHttpClientConnectionManager getManager() {
        return connMrg;
    }

    public CloseableHttpClient getHttpClient() {
        return HttpClients.custom().setConnectionManager(connMrg).build();
    }

    /**
     * 获取忽略证书的HttpClient
     * 
     * @return
     */
    public CloseableHttpClient getHttpsClient() {
        return getHttpsClient(createSSLConnSocketFactory());
    }

    public CloseableHttpClient getHttpsClient(SSLConnectionSocketFactory sslSocketFactory) {
        return HttpClients.custom().setSSLSocketFactory(sslSocketFactory).setConnectionManager(connMrg).build();
    }

    /**
     * 创建SSL安全连接
     * 
     * @return
     */
    private SSLConnectionSocketFactory createSSLConnSocketFactory() {
        SSLConnectionSocketFactory sslsf = null;
        try {
            SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() {

                public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                    // 信任所有
                    return true;
                }

            }).build();
            sslsf = new SSLConnectionSocketFactory(sslContext);
        } catch (GeneralSecurityException e) {
            e.printStackTrace();
        }
        return sslsf;
    }
}


然而我们在使用的时候,需求是需要连接多个不同的服务器,所以需要多个PoolingHttpClientConnectionManager。然后再上一份代码~

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

import org.apache.http.impl.client.CloseableHttpClient;

/**
 * HttpClient连接池工厂<br/>
 * Author:杨杰超<br/>
 * Date:2018年3月12日 下午3:16:18 <br/>
 * Copyright (c) 2018, yangjiechao@dingtalk.com All Rights Reserved.<br/>
 *
 */
public class GlobalHttpClientConnectionManagerFactory {

    // 超时参数
    public static final long timeToLive = 10;
    // 超时参数单位
    public static final TimeUnit tunit = TimeUnit.SECONDS;
    // 设置整个连接池最大连接数
    public static final int maxTotal = 256;
    // 单个路由最大连接数
    public static final int defaultMaxPerRoute = 256;

    public static Map<String, GlobalHttpClientConnectionManager> cache = new ConcurrentHashMap<>();

    public static GlobalHttpClientConnectionManager getGlobalHttpClientConnectionManager(String key) {
        return getGlobalHttpClientConnectionManager(key, timeToLive, tunit, maxTotal, defaultMaxPerRoute);
    }

    public static GlobalHttpClientConnectionManager getGlobalHttpClientConnectionManager(String key, long timeToLive,
            TimeUnit tunit, int maxTotal, int defaultMaxPerRoute) {
        GlobalHttpClientConnectionManager manager = cache.get(key);
        if (null == manager) {
            synchronized (cache) {
                manager = cache.get(key);
                if (null == manager) {
                    manager = new GlobalHttpClientConnectionManager(timeToLive, tunit, maxTotal, defaultMaxPerRoute);
                    cache.put(key, manager);
                }
            }
        }
        return manager;
    }

    public static CloseableHttpClient getCloseableHttpClient(String key) {
        return getCloseableHttpClient(key, timeToLive, tunit, maxTotal, defaultMaxPerRoute);
    }

    public static CloseableHttpClient getCloseableHttpClient(String key, long timeToLive, TimeUnit tunit, int maxTotal,
            int defaultMaxPerRoute) {
        return getGlobalHttpClientConnectionManager(key, timeToLive, tunit, maxTotal, defaultMaxPerRoute)
                .getHttpClient();
    }

}

这货版本更新变化得太多了,加上jsoup做抓取真不错~



  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Jc_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值