欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

java http連接池的實(shí)現(xiàn)方式(帶有失敗重試等高級(jí)功能)

 更新時(shí)間:2024年04月28日 14:45:33   作者:苦蕎米  
這篇文章主要介紹了java http連接池的實(shí)現(xiàn)方式(帶有失敗重試等高級(jí)功能),具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

java 本身提供的java.net.HttpURLConnection不支持連接池功能。

如果不想從頭實(shí)現(xiàn)的話,最好的方式便是引用第三方依賴包,目前是有一個(gè)特別不錯(cuò)的,org.apache.httpcomponents:httpclient依賴

引入方式如下:

<dependency>
	<groupId>org.apache.httpcomponents</groupId>
	<artifactId>httpclient</artifactId>
	<version>4.5.13</version>
</dependency>

使用httpclient依賴

在開始使用連接池之前,要學(xué)會(huì)如何使用httpclient去完成http請(qǐng)求,其請(qǐng)求方式與java的原生http請(qǐng)求完全不同。

其中CloseableHttpClient對(duì)象便是我們的http請(qǐng)求連接池,其實(shí)聲明方式會(huì)在下面介紹。

// 引用的包
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.*;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class DoHttp {
	private static final Logger LOG = LoggerFactory.getLogger(DoHttp.class);
	// httpGet請(qǐng)求
	public static String get(CloseableHttpClient httpClient, String url) {
	    HttpGet httpGet = new HttpGet(url);
	    return doRequest(httpClient, url, httpGet);
	}
	// httpPost請(qǐng)求 (json格式)
	public static String jsonPost(CloseableHttpClient httpClient, String url, String json) {
	    HttpPost httpPost = new HttpPost(url);
	    httpPost.setHeader("Content-Type", "application/json");
	    StringEntity entity = new StringEntity(json, "UTF-8");
	    httpPost.setEntity(entity);
	    return doRequest(httpClient, url, httpPost);
	}
	// 統(tǒng)一的請(qǐng)求處理邏輯
	private static String doRequest(CloseableHttpClient httpClient, String url, HttpRequestBase httpRequest) {
	    try (CloseableHttpResponse response = httpClient.execute(httpRequest)) {
	        int code = response.getStatusLine().getStatusCode();
	        HttpEntity responseEntity = response.getEntity();
	        String responseBody = null;
	        if (responseEntity != null) {
	            responseBody = EntityUtils.toString(responseEntity);
	        }
	        if (code != 200) {
	            LOG.error("http post error, url: {}, code: {}, result: {}", url, code, responseBody);
	            return null;
	        }
	        return responseBody;
	    } catch (Exception e) {
	        LOG.error("http post error, url: {}", url, e);
	    }
	    return null;
	}
}

連接池的實(shí)現(xiàn)

連接池的配置類

如下:

public class HttpPoolConfig {
    /** http連接池大小 */
    public int httpPoolSize;
    /** http連接超時(shí)時(shí)間 */
    public int httpConnectTimeout;
    /** http連接池等待超時(shí)時(shí)間 */
    public int httpWaitTimeout;
    /** http響應(yīng)包間隔超時(shí)時(shí)間 */
    public int httpSocketTimeout;
    /** http重試次數(shù) */
    public int httpRetryCount;
    /** http重試間隔時(shí)間 */
    public int httpRetryInterval;
    /** http監(jiān)控間隔時(shí)間 定時(shí)清理 打印連接池狀態(tài) */
    public int httpMonitorInterval;
    /** http關(guān)閉空閑連接的等待時(shí)間 */
    public int httpCloseIdleConnectionWaitTime;
}

連接池實(shí)現(xiàn)類

import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpRequest;
import org.apache.http.NoHttpResponseException;
import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.LayeredConnectionSocketFactory;
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.pool.PoolStats;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.net.ssl.SSLException;
import java.io.InterruptedIOException;
import java.net.UnknownHostException;
import java.util.Map;
import java.util.TimerTask;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * http連接池
 */
public class HttpPool {

    private static final Logger LOG = LoggerFactory.getLogger(HttpPool.class);

    /**
     * 初始化連接池
     * @param httpPoolConfig 配置信息
     */
    public HttpPool(HttpPoolConfig httpPoolConfig) {
        PoolingHttpClientConnectionManager manager = buildHttpManger(httpPoolConfig);
        httpClient = buildHttpClient(httpPoolConfig, manager);
        monitorExecutor = buildMonitorExecutor(httpPoolConfig, manager);
    }

    private final CloseableHttpClient httpClient;
    private final ScheduledExecutorService monitorExecutor;

    /**
     * 連接池管理器
     */
    private PoolingHttpClientConnectionManager buildHttpManger(HttpPoolConfig httpPoolConfig) {
        LayeredConnectionSocketFactory sslSocketFactory = SSLConnectionSocketFactory.getSocketFactory();
        Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
                .register("https", sslSocketFactory).build();
        PoolingHttpClientConnectionManager manager = new PoolingHttpClientConnectionManager(registry);
        manager.setMaxTotal(httpPoolConfig.httpPoolSize);
        manager.setDefaultMaxPerRoute(httpPoolConfig.httpPoolSize);
        return manager;
    }

    /**
     * 建立httpClient
     */
    private CloseableHttpClient buildHttpClient(HttpPoolConfig httpPoolConfig, PoolingHttpClientConnectionManager manager) {
        // 請(qǐng)求配置
        RequestConfig config = RequestConfig.custom()
                .setConnectTimeout(httpPoolConfig.httpConnectTimeout)
                .setSocketTimeout(httpPoolConfig.httpSocketTimeout)
                .setConnectionRequestTimeout(httpPoolConfig.httpWaitTimeout)
                .build();
        // 失敗重試機(jī)制
        HttpRequestRetryHandler retryHandler = (e, c, context) -> {
            if (c > httpPoolConfig.httpRetryCount) {
                LOG.error("HttpPool request retry more than {} times", httpPoolConfig.httpRetryCount, e);
                return false;
            }
            if (e == null) {
                LOG.info("HttpPool request exception is null.");
                return false;
            }
            if (e instanceof NoHttpResponseException) {
                //服務(wù)器沒有響應(yīng),可能是服務(wù)器斷開了連接,應(yīng)該重試
                LOG.error("HttpPool receive no response from server, retry");
                return true;
            }
            // SSL握手異常
            if (e instanceof InterruptedIOException // 超時(shí)
                    || e instanceof UnknownHostException // 未知主機(jī)
                    || e instanceof SSLException) { // SSL異常
                LOG.error("HttpPool request error, retry", e);
                return true;
            } else {
                LOG.error("HttpPool request unknown error, retry", e);
            }
            // 對(duì)于關(guān)閉連接的異常不進(jìn)行重試
            HttpClientContext clientContext = HttpClientContext.adapt(context);
            HttpRequest request = clientContext.getRequest();
            return !(request instanceof HttpEntityEnclosingRequest);
        };
        // 構(gòu)建httpClient
        return HttpClients.custom().setDefaultRequestConfig(config)
                .setConnectionManager(manager).setRetryHandler(retryHandler).build();
    }

    /**
     * 建立連接池監(jiān)視器
     */
    private ScheduledExecutorService buildMonitorExecutor(HttpPoolConfig httpPoolConfig,
                                                          PoolingHttpClientConnectionManager manager) {
        TimerTask timerTask = new TimerTask() {
            @Override
            public void run() {
                // 關(guān)閉過期連接
                manager.closeExpiredConnections();
                // 關(guān)閉空閑時(shí)間超過一定時(shí)間的連接
                manager.closeIdleConnections(httpPoolConfig.httpCloseIdleConnectionWaitTime, TimeUnit.MILLISECONDS);
                // 打印連接池狀態(tài)
                PoolStats poolStats = manager.getTotalStats();
                // max:最大連接數(shù), available:可用連接數(shù), leased:已借出連接數(shù), pending:掛起(表示當(dāng)前等待從連接池中獲取連接的線程數(shù)量)
                LOG.info("HttpPool status {}", poolStats);
            }
        };
        ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
        int time = httpPoolConfig.httpMonitorInterval;
        executor.scheduleAtFixedRate(timerTask, time, time, TimeUnit.MILLISECONDS);
        return executor;
    }

    /**
     * 關(guān)閉連接池
     */
    public void close() {
        try {
            httpClient.close();
            monitorExecutor.shutdown();
        } catch (Exception e) {
            LOG.error("HttpPool close http client error", e);
        }
    }

    /**
     * 發(fā)起get請(qǐng)求
     */
    public String get(String url) { return DoHttp.get(httpClient, url); }

    /**
     * 發(fā)起json格式的post請(qǐng)求
     */
    public String jsonPost(String url, String json) { return DoHttp.jsonPost(httpClient, url, json); }
}

總結(jié)

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • SpringBoot如何返回Json數(shù)據(jù)格式

    SpringBoot如何返回Json數(shù)據(jù)格式

    這篇文章主要介紹了SpringBoot如何返回Json數(shù)據(jù)格式問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-03-03
  • JAVA中的日期LocalDate類詳細(xì)用法講解

    JAVA中的日期LocalDate類詳細(xì)用法講解

    Java中存在一個(gè)日歷表示法的類庫,LocalDate類,如果只想要指定的年月日就可以用這個(gè)LocalDate類,下面這篇文章主要給大家介紹了關(guān)于JAVA中日期LocalDate類詳細(xì)用法講解的相關(guān)資料,需要的朋友可以參考下
    2024-01-01
  • Java編寫簡(jiǎn)單計(jì)算器的完整實(shí)現(xiàn)過程

    Java編寫簡(jiǎn)單計(jì)算器的完整實(shí)現(xiàn)過程

    這篇文章主要給大家介紹了關(guān)于Java編寫簡(jiǎn)單計(jì)算器的完整實(shí)現(xiàn)過程,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-12-12
  • Vue3實(shí)現(xiàn)多頁面跳轉(zhuǎn)效果的幾種方式

    Vue3實(shí)現(xiàn)多頁面跳轉(zhuǎn)效果的幾種方式

    Vue.js是一個(gè)用于構(gòu)建用戶界面的漸進(jìn)式 JavaScript 框架,它提供了多種方法來實(shí)現(xiàn)頁面之間的導(dǎo)航,在 Vue 3 中,頁面跳轉(zhuǎn)主要通過 Vue Router 來管理,同時(shí)也支持其他方式如編程式導(dǎo)航和使用錨點(diǎn)鏈接,本文將詳細(xì)介紹 Vue 3 中的各種頁面跳轉(zhuǎn)方式,需要的朋友可以參考下
    2025-03-03
  • Java String 字符串常量池解析

    Java String 字符串常量池解析

    這篇文章主要介紹了Java String 字符串常量池解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-08-08
  • java中stringbuffer線程安全分析實(shí)例詳解

    java中stringbuffer線程安全分析實(shí)例詳解

    在本篇文章里小編給大家整理的是一篇關(guān)于java中stringbuffer線程安全分析實(shí)例詳解內(nèi)容,有興趣的朋友們可以學(xué)習(xí)下。
    2021-01-01
  • springcloud下hibernate本地化方言配置方式

    springcloud下hibernate本地化方言配置方式

    這篇文章主要介紹了springcloud下hibernate本地化方言配置方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-09-09
  • Springboot整合quartz產(chǎn)生錯(cuò)誤及解決方案

    Springboot整合quartz產(chǎn)生錯(cuò)誤及解決方案

    這篇文章主要介紹了Springboot整合quartz產(chǎn)生錯(cuò)誤及解決方案,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-06-06
  • Spring入門到精通之注解開發(fā)詳解

    Spring入門到精通之注解開發(fā)詳解

    Spring是輕代碼而重配置的框架,配置比較繁重,影響開發(fā)效率,所以注解開發(fā)是一種趨勢(shì)。本文將通過示例為大家詳細(xì)講講Spring如何實(shí)現(xiàn)注解開發(fā),感興趣的可以學(xué)習(xí)一下
    2022-07-07
  • java判斷用戶輸入的是否至少含有N位小數(shù)的實(shí)例

    java判斷用戶輸入的是否至少含有N位小數(shù)的實(shí)例

    下面小編就為大家分享一篇java判斷用戶輸入的是否至少含有N位小數(shù)的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2017-12-12

最新評(píng)論