HttpClient 4.5.2-(五)連接池的配置

緊接上一節(jié)亿鲜,本節(jié)記錄 【連接池的配置】
  兩個主機建立連接的過程是很復雜的一個過程冤吨,涉及到多個數(shù)據(jù)包的交換漩蟆,并且也很耗時間怠李。Http連接需要的三次握手開銷很大,這一開銷對于比較小的http消息來說更大夷蚊。但是如果我們直接使用已經(jīng)建立好的http連接惕鼓,這樣花費就比較小唐础,吞吐率更大彻犁。


修改代碼

上節(jié)代碼的基礎(chǔ)上汞幢,我們添加全局靜態(tài)變量連接池管理對象森篷,提供靜態(tài)代碼塊初始化連接池管理對象.

  • 初始化
......前省略

/**
 * Http請求工具類
 * 
 * @author 大漠知秋
 */
public class HttpRequestUtils {

    /** 全局連接池對象 */
    private static final PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(); 
    
    /**
     * 靜態(tài)代碼塊配置連接池信息
     */
    static {
        
        // 設置最大連接數(shù)
        connManager.setMaxTotal(200);
        // 設置每個連接的路由數(shù)
        connManager.setDefaultMaxPerRoute(20);
        
    }
    
    /**
     * 獲取Http客戶端連接對象
     * 
     * @param timeOut 超時時間
     * @return Http客戶端連接對象
     */
    public static CloseableHttpClient getHttpClient(Integer timeOut) {

......后省略

PoolingHttpClientConnectionManager是個復雜的類仲智,它管理著連接池钓辆,可以同時為很多線程提供http連接請求。當請求一個新的連接時前联,如果連接池有可用的持久連接,連接管理器就會使用其中的一個啸臀,而不是再創(chuàng)建一個新的連接乘粒。

PoolingHttpClientConnectionManager維護的連接數(shù)在每個路由基礎(chǔ)和總數(shù)上都有限制灯萍。默認旦棉,每個路由基礎(chǔ)上的連接不超過2個,總連接數(shù)不能超過20他爸。在實際應用中诊笤,這個限制可能會太小了讨跟,尤其是當服務器也使用Http協(xié)議時晾匠。此處我們設置為最高200個總連接數(shù)和每個基礎(chǔ)路由連接不超過20個凉馆。

  • 已經(jīng)在全局聲明Http連接池管理工具澜共,配置進httpClient連接客戶端
/**
 * 獲取Http客戶端連接對象
 * 
 * @param timeOut 超時時間
 * @return Http客戶端連接對象
 */
public static CloseableHttpClient getHttpClient(Integer timeOut) {
    // 創(chuàng)建Http請求配置參數(shù)
    RequestConfig requestConfig = RequestConfig.custom()
        // 獲取連接超時時間
        .setConnectionRequestTimeout(timeOut)
        // 請求超時時間
        .setConnectTimeout(timeOut)
        // 響應超時時間
        .setSocketTimeout(timeOut)
        .build();
    
    /**
     * 測出超時重試機制為了防止超時不生效而設置
     *  如果直接放回false,不重試
     *  這里會根據(jù)情況進行判斷是否重試
     */
    HttpRequestRetryHandler retry = new HttpRequestRetryHandler() {
        @Override
        public boolean retryRequest(IOException exception, int executionCount, HttpContext context) {
            if (executionCount >= 3) {// 如果已經(jīng)重試了3次嗦董,就放棄
                return false;
            }
            if (exception instanceof NoHttpResponseException) {// 如果服務器丟掉了連接奇唤,那么就重試
                return true;
            }
            if (exception instanceof SSLHandshakeException) {// 不要重試SSL握手異常
                return false;
            }
            if (exception instanceof InterruptedIOException) {// 超時
                return true;
            }
            if (exception instanceof UnknownHostException) {// 目標服務器不可達
                return false;
            }
            if (exception instanceof ConnectTimeoutException) {// 連接被拒絕
                return false;
            }
            if (exception instanceof SSLException) {// ssl握手異常
                return false;
            }
            HttpClientContext clientContext = HttpClientContext.adapt(context);
            HttpRequest request = clientContext.getRequest();
            // 如果請求是冪等的咬扇,就再次嘗試
            if (!(request instanceof HttpEntityEnclosingRequest)) {
                return true;
            }
            return false;
        }
    };
    
    // 創(chuàng)建httpClient
    return HttpClients.custom()
            // 把請求相關(guān)的超時信息設置到連接客戶端
            .setDefaultRequestConfig(requestConfig)
            // 把請求重試設置到連接客戶端
            .setRetryHandler(retry)
            // 配置連接池管理對象
            .setConnectionManager(connManager)
            .build();
}

在上方創(chuàng)建httpClient處把連接池管理對象配置到連接客戶端中

  • 最后完整代碼
package com.lynchj.writing;

import java.io.IOException;
import java.io.InterruptedIOException;
import java.net.UnknownHostException;

import javax.net.ssl.SSLException;
import javax.net.ssl.SSLHandshakeException;

import org.apache.http.HttpEntity;
import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpRequest;
import org.apache.http.NoHttpResponseException;
import org.apache.http.ParseException;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.conn.ConnectTimeoutException;
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.protocol.HttpContext;
import org.apache.http.util.EntityUtils;

/**
 * Http請求工具類
 * 
 * @author 大漠知秋
 */
public class HttpRequestUtils {

    /** 全局連接池對象 */
    private static final PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(); 
    
    /**
     * 靜態(tài)代碼塊配置連接池信息
     */
    static {
        
        // 設置最大連接數(shù)
        connManager.setMaxTotal(200);
        // 設置每個連接的路由數(shù)
        connManager.setDefaultMaxPerRoute(20);
        
    }
    
    /**
     * 獲取Http客戶端連接對象
     * 
     * @param timeOut 超時時間
     * @return Http客戶端連接對象
     */
    public static CloseableHttpClient getHttpClient(Integer timeOut) {
        // 創(chuàng)建Http請求配置參數(shù)
        RequestConfig requestConfig = RequestConfig.custom()
            // 獲取連接超時時間
            .setConnectionRequestTimeout(timeOut)
            // 請求超時時間
            .setConnectTimeout(timeOut)
            // 響應超時時間
            .setSocketTimeout(timeOut)
            .build();
        
        /**
         * 測出超時重試機制為了防止超時不生效而設置
         *  如果直接放回false,不重試
         *  這里會根據(jù)情況進行判斷是否重試
         */
        HttpRequestRetryHandler retry = new HttpRequestRetryHandler() {
            @Override
            public boolean retryRequest(IOException exception, int executionCount, HttpContext context) {
                if (executionCount >= 3) {// 如果已經(jīng)重試了3次隅居,就放棄
                    return false;
                }
                if (exception instanceof NoHttpResponseException) {// 如果服務器丟掉了連接胎源,那么就重試
                    return true;
                }
                if (exception instanceof SSLHandshakeException) {// 不要重試SSL握手異常
                    return false;
                }
                if (exception instanceof InterruptedIOException) {// 超時
                    return true;
                }
                if (exception instanceof UnknownHostException) {// 目標服務器不可達
                    return false;
                }
                if (exception instanceof ConnectTimeoutException) {// 連接被拒絕
                    return false;
                }
                if (exception instanceof SSLException) {// ssl握手異常
                    return false;
                }
                HttpClientContext clientContext = HttpClientContext.adapt(context);
                HttpRequest request = clientContext.getRequest();
                // 如果請求是冪等的,就再次嘗試
                if (!(request instanceof HttpEntityEnclosingRequest)) {
                    return true;
                }
                return false;
            }
        };
        
        // 創(chuàng)建httpClient
        return HttpClients.custom()
                // 把請求相關(guān)的超時信息設置到連接客戶端
                .setDefaultRequestConfig(requestConfig)
                // 把請求重試設置到連接客戶端
                .setRetryHandler(retry)
                // 配置連接池管理對象
                .setConnectionManager(connManager)
                .build();
    }
    
    /**
     * GET請求
     * 
     * @param url 請求地址
     * @param timeOut 超時時間
     * @return
     */
    public static String httpGet(String url, Integer timeOut) {
        String msg = "-1";
        
        // 獲取客戶端連接對象
        CloseableHttpClient httpClient = getHttpClient(timeOut);
        // 創(chuàng)建GET請求對象
        HttpGet httpGet = new HttpGet(url);
        
        CloseableHttpResponse response = null;
        
        try {
            // 執(zhí)行請求
            response = httpClient.execute(httpGet);
            // 獲取響應實體
            HttpEntity entity = response.getEntity();
            // 獲取響應信息
            msg = EntityUtils.toString(entity, "UTF-8");
        } catch (ClientProtocolException e) {
            System.err.println("協(xié)議錯誤");
            e.printStackTrace();
        } catch (ParseException e) {
            System.err.println("解析錯誤");
            e.printStackTrace();
        } catch (IOException e) {
            System.err.println("IO錯誤");
            e.printStackTrace();
        } finally {
            if (null != response) {
                try {
                    EntityUtils.consume(response.getEntity());
                    response.close();
                } catch (IOException e) {
                    System.err.println("釋放鏈接錯誤");
                    e.printStackTrace();
                }
            }
        }
        
        return msg;
    }
    
    public static void main(String[] args) {
        
        System.out.println(httpGet("http://www.baidu.com", 6000));
        
    }
    
}

本節(jié)完畢,下一節(jié)記錄【安全的SSL/TLS連接-繞過證書】

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末西疤,一起剝皮案震驚了整個濱河市烦粒,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌代赁,老刑警劉巖扰她,帶你破解...
    沈念sama閱讀 206,968評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異芭碍,居然都是意外死亡徒役,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評論 2 382
  • 文/潘曉璐 我一進店門窖壕,熙熙樓的掌柜王于貴愁眉苦臉地迎上來忧勿,“玉大人,你說我怎么就攤上這事瞻讽『桑” “怎么了?”我有些...
    開封第一講書人閱讀 153,220評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長乖寒。 經(jīng)常有香客問我,道長逐虚,這世上最難降的妖魔是什么漱病? 我笑而不...
    開封第一講書人閱讀 55,416評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上山害,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好汹想,可當我...
    茶點故事閱讀 64,425評論 5 374
  • 文/花漫 我一把揭開白布槽唾。 她就那樣靜靜地躺著,像睡著了一般恋博。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上秦士,一...
    開封第一講書人閱讀 49,144評論 1 285
  • 那天曹傀,我揣著相機與錄音,去河邊找鬼幕庐。 笑死,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的督怜。 我是一名探鬼主播丰歌,決...
    沈念sama閱讀 38,432評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼偷仿,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起薄榛,我...
    開封第一講書人閱讀 37,088評論 0 261
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎啸蜜,沒想到半個月后呢岗,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,586評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡惫霸,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,028評論 2 325
  • 正文 我和宋清朗相戀三年射窒,在試婚紗的時候發(fā)現(xiàn)自己被綠了点寥。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片责鳍。...
    茶點故事閱讀 38,137評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡乓诽,死狀恐怖稠集,靈堂內(nèi)的尸體忽然破棺而出晦鞋,到底是詐尸還是另有隱情确买,我是刑警寧澤撑帖,帶...
    沈念sama閱讀 33,783評論 4 324
  • 正文 年R本政府宣布缴罗,位于F島的核電站舌界,受9級特大地震影響藐握,放射性物質(zhì)發(fā)生泄漏抬闷。R本人自食惡果不足惜炕泳,卻給世界環(huán)境...
    茶點故事閱讀 39,343評論 3 307
  • 文/蒙蒙 一皇耗、第九天 我趴在偏房一處隱蔽的房頂上張望敌买。 院中可真熱鬧芜抒,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽躏吊。三九已至,卻和暖如春赁项,著一層夾襖步出監(jiān)牢的瞬間肤舞,已是汗流浹背篙顺。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評論 1 262
  • 我被黑心中介騙來泰國打工宰僧, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 45,595評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像荆残,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子净当,可洞房花燭夜當晚...
    茶點故事閱讀 42,901評論 2 345

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理内斯,服務發(fā)現(xiàn),斷路器像啼,智...
    卡卡羅2017閱讀 134,601評論 18 139
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 171,522評論 25 707
  • 還有三天我就要結(jié)婚了俘闯,可是我一點兒也高興不起來。冥冥中覺得忽冻,即使這婚結(jié)了真朗,過不了兩三年,這場婚姻也會以離婚而告終僧诚。...
    青芒不茫閱讀 434評論 9 5
  • 【0918今日剽悍】 假如你手頭的工作很多遮婶,領(lǐng)導又交給了你另一項工作,你很是郁悶湖笨。這個時候旗扑,你應該靜下心來,去看看...
    好聽的暖陽閱讀 181評論 0 0