HttpClientを使用:APIデータベース接続プール

1.なぜ、接続プールの場合?

  • 確立と解放されたとき、廃TCPコネクションのソケット通信のサーバーリソースを削減、頻繁にセットアップ時間HTTP接続のオーバーヘッドを削減。
  • 同時の高い数をサポートしています。

2、従来のAPI接続プールのHttpClient

本明細書で使用する場合、以下の内容が記述されたバージョンに基づいているので、それは、HttpClient4.5.3の最新バージョンです。

  • PoolingHttpClientConnectionManager接続プール管理の実装クラス
    PoolingHttpClientConnectionManagerHttpClientを、接続プールのクラスを実現する実装HttpClientConnectionManager和ConnPoolControlインタフェース。
  • コンストラクタ:PoolingHttpClientConnectionManager():コンストラクタは、引数なしで、あなたはメソッドからソースコードを見ることができるプロトコルのHTTPおよびHTTPSプロトコルを登録するgetDefaultRegistry()を呼び出します。
  • 一般的な方法:
    公共のボイドsetMaxTotal(int型の最大値)。 ConnPoolControlインタフェースで定義された方法は、最大接続数が最大提供される表します。
    公共のボイドsetDefaultMaxPerRoute(int型の最大): この方法はまた、ConnPoolControlインタフェースで定義され、それが最大にデフォルトルートごとの接続の最大数を表します
    公共のボイドsetMaxPerRoute(HttpRouteルート、int型の最大値) 接続指定されたルートのセットの最大数は、この構成は、経路setDefaultMaxPerRouteの値を上書きします。
  • 一般的な方法:
    静的RequestConfig.Builderカスタム():ビルダーオブジェクトを作成し、パラメータを設定するための静的メソッド;
    int型getConnectionRequestTimeout():ミリ秒単位で、最大時間から取得した接続プールを取得します。
    int型getConnectTimeout() :ミリ秒単位で、最長の接続を作成しなさい;
    int型getSocketTimeout():ミリ秒単位で、データ伝送のための最大時間を取得します。
  • :RequestConfigはBuilderは、便利に構築RequestConfigオブジェクトとパラメータ設定要求のために、このような従来の方法は、次のしている内部の静的クラスを持つ
    公共RequestConfig.Builder setConnectionRequestTimeout(connectionRequestTimeout INT):接続プールからのミリ秒単位で、接続の最大時間の設定を取得します。 。
    公共RequestConfig.Builder setConnectTimeoutは(INTのconnecttimeout):ミリ秒単位で、接続の設定された最大時間を作成し、
    パブリックRequestConfig.Builder setSocketTimeout(INT socketTimeout):ミリ秒単位で、データ伝送のための最大時間を設定;.
  • HttpRequestRetryHandler要求リトライインタフェース
    ブールretryRequest(IOExceptionを例外、INT executionCount 、org.apache.http.protocol.HttpContextコンテキスト): 実装IO異常の実行中に発生した場合、インターフェイスがこの方法は、決定は、このメソッドを実装する必要があり、SHOULD再試行、再試行executionCount回。

3、シングルスレッド - HTTPリクエストを使用して、接続プール管理プログラム

  • 示すように、HTTP接続プール管理オブジェクトのCMを作成します。
PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
  • 以下のように、各経路およびデフォルト接続パラメータの最大数の最大接続数を設定します
//将最大连接数增加到200
 cm.setMaxTotal(200);
//将每个路由的默认最大连接数增加到20
 cm.setDefaultMaxPerRoute(20);
  • オブジェクトがIO異常な必要性処理を実行するとき、すなわちインタフェースHttpRequestRetryHandlerを実装するために、接続プール・オブジェクトを設定するために、接続プールから取得する必要があることHTTPGET HttpPostアナログ送信要求又はHttpClientsを作成するための要求注;これは処理することを注意閉鎖接続プールが破壊される場合に要求に応じて、HttpClientを対象閉じることができません。HttpClientsオブジェクトが示されたオブジェクトを作成します。
CloseableHttpClient httpClient = HttpClients.custom()
                .setConnectionManager(connectionManager)
                .setRetryHandler(retryHandler(5)).build();
  • 接続プールのアイドル状態の接続を監視するスレッドを開き、不正な接続をクリーンアップすることができ、あなた自身の周波数モニタスレッドを設定することができます
  • コードの実装
package com.liangpj.develop.httpclient;
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.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.conn.HttpClientConnectionManager;
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;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLHandshakeException;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.net.UnknownHostException;

/**
 * 单线程-使用连接池管理HTTP请求
 * @author: liangpengju
 * @version: 1.0
 */
public class HttpConnectManager {

    public static void main(String[] args) throws Exception {
        //创建HTTP的连接池管理对象
        PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager();
        //将最大连接数增加到200
        connectionManager.setMaxTotal(200);
        //将每个路由的默认最大连接数增加到20
        connectionManager.setDefaultMaxPerRoute(20);
        //将http://www.baidu.com:80的最大连接增加到50
        //HttpHost httpHost = new HttpHost("http://www.baidu.com",80);
        //connectionManager.setMaxPerRoute(new HttpRoute(httpHost),50);

        //发起3次GET请求
        String url ="https://www.baidu.com/s?word=java";
        long start = System.currentTimeMillis();
        for (int i=0;i<100;i++){
            doGet(connectionManager,url);
        }
        long end = System.currentTimeMillis();
        System.out.println("consume -> " + (end - start));

        //清理无效连接
        new IdleConnectionEvictor(connectionManager).start();
    }

    /**
     * 请求重试处理
     * @param tryTimes 重试次数
     * @return
     */
    public static HttpRequestRetryHandler retryHandler(final int tryTimes){

        HttpRequestRetryHandler httpRequestRetryHandler = new HttpRequestRetryHandler() {
            @Override
            public boolean retryRequest(IOException exception, int executionCount, HttpContext context) {
                // 如果已经重试了n次,就放弃
                if (executionCount >= tryTimes) {
                    return false;
                }
                // 如果服务器丢掉了连接,那么就重试
                if (exception instanceof NoHttpResponseException) {
                    return true;
                }
                // 不要重试SSL握手异常
                if (exception instanceof SSLHandshakeException) {
                    return false;
                }
                // 超时
                if (exception instanceof InterruptedIOException) {
                    return false;
                }
                // 目标服务器不可达
                if (exception instanceof UnknownHostException) {
                    return true;
                }
                // 连接被拒绝
                if (exception instanceof ConnectTimeoutException) {
                    return false;
                }
                // SSL握手异常
                if (exception instanceof SSLException) {
                    return false;
                }
                HttpClientContext clientContext = HttpClientContext .adapt(context);
                HttpRequest request = clientContext.getRequest();
                // 如果请求是幂等的,就再次尝试
                if (!(request instanceof HttpEntityEnclosingRequest)) {
                    return true;
                }
                return false;
            }
        };
        return httpRequestRetryHandler;
    }

    /**
     * doGet
     * @param url 请求地址
     * @param connectionManager
     * @throws Exception
     */
    public static void doGet(HttpClientConnectionManager connectionManager,String url) throws Exception {
        //从连接池中获取client对象,多例
        CloseableHttpClient httpClient = HttpClients.custom()
                .setConnectionManager(connectionManager)
                .setRetryHandler(retryHandler(5)).build();

        // 创建http GET请求
        HttpGet httpGet = new HttpGet(url);
        // 构建请求配置信息
        RequestConfig config = RequestConfig.custom().setConnectTimeout(1000) // 创建连接的最长时间
                .setConnectionRequestTimeout(500) // 从连接池中获取到连接的最长时间
                .setSocketTimeout(10 * 1000) // 数据传输的最长时间10s
                .setStaleConnectionCheckEnabled(true) // 提交请求前测试连接是否可用
                .build();
        // 设置请求配置信息
        httpGet.setConfig(config);

        CloseableHttpResponse response = null;
        try {
            // 执行请求
            response = httpClient.execute(httpGet);
            // 判断返回状态是否为200
            if (response.getStatusLine().getStatusCode() == 200) {
                String content = EntityUtils.toString(response.getEntity(), "UTF-8");
                System.out.println("内容长度:" + content.length());
            }
        } finally {
            if (response != null) {
                response.close();
            }
            // 此处不能关闭httpClient,如果关闭httpClient,连接池也会销毁
            // httpClient.close();
        }
    }

    /**
     * 监听连接池中空闲连接,清理无效连接
     */
    public static class IdleConnectionEvictor extends Thread {

        private final HttpClientConnectionManager connectionManager;

        private volatile boolean shutdown;

        public IdleConnectionEvictor(HttpClientConnectionManager connectionManager) {
            this.connectionManager = connectionManager;
        }

        @Override
        public void run() {
            try {
                while (!shutdown) {
                    synchronized (this) {
                        //3s检查一次
                        wait(3000);
                        // 关闭失效的连接
                        connectionManager.closeExpiredConnections();
                    }
                }
            } catch (InterruptedException ex) {
                // 结束
                ex.printStackTrace();
            }
        }

        public void shutdown() {
            shutdown = true;
            synchronized (this) {
                notifyAll();
            }
        }
    }
}

図4に示すように、マルチスレッド接続プールマネージャ-HttpClient例HTTPリクエスト

  • 示すように、HTTP接続プール管理オブジェクトのCMを作成します。
PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
  • 以下のように、各経路およびデフォルト接続パラメータの最大数の最大接続数を設定します
//将最大连接数增加到200
 cm.setMaxTotal(200);
//将每个路由的默认最大连接数增加到20
 cm.setDefaultMaxPerRoute(20);
  • HttpClientsが作成され、接続プールのオブジェクトを提供するオブジェクト、HttpClientsオブジェクトに示すオブジェクトを作成します。
CloseableHttpClient httpClient = HttpClients.custom().setConnectionManager(connectionManager).build()
  • Getリクエストの実行スレッドクラスGetThread、オーバーロードrun()メソッド、リクエスト実行HTTPGETを達成するために、Threadクラスの継承
  • 要求にURIアドレスが配列として定義され、GetThread各URIのスレッドを作成し、すべてのスレッドを起動します
package com.liangpj.develop.httpclient;
import org.apache.http.HttpEntity;
import org.apache.http.client.ClientProtocolException;
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.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.protocol.HttpContext;
import java.io.IOException;

/**
 * 多线程-HttpClient连接池管理HTTP请求实例
 */
public class MultiThreadHttpConnManager {
    public static void main(String[] args) {
        //连接池对象
        PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager();
      //将最大连接数增加到200
        connectionManager.setMaxTotal(200);
        //将每个路由的默认最大连接数增加到20
        connectionManager.setDefaultMaxPerRoute(20);
        //HttpClient对象
        CloseableHttpClient httpClient = HttpClients.custom().setConnectionManager(connectionManager).build();
        //URIs to DoGet
        String[] urisToGet = {
                "https://www.baidu.com/s?word=java",
                "https://www.baidu.com/s?word=java",
                "https://www.baidu.com/s?word=java",
                "https://www.baidu.com/s?word=java"
        };
        //为每一个URI创建一个线程
        GetThread[] threads = new GetThread[urisToGet.length];
        for (int i=0;i<threads.length;i++){
            HttpGet httpGet = new HttpGet(urisToGet[i]);
            threads[i] = new GetThread(httpClient,httpGet);
        }
        //启动线程
        for (int j=0;j<threads.length;j++){
            threads[j].start();
        }
        //join 线程
        for(int k=0;k<threads.length;k++){
            try {
                threads[k].join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 执行Get请求线程
     */
    public static class GetThread extends Thread{
        private final CloseableHttpClient httpClient;
        private final HttpContext context;
        private final HttpGet httpget;
        public GetThread(CloseableHttpClient httpClient, HttpGet httpget) {
            this.httpClient = httpClient;
            this.context = HttpClientContext.create();
            this.httpget = httpget;
        }
        @Override
        public void run() {
            try {
                CloseableHttpResponse response = httpClient.execute(httpget,context);
                try {
                    HttpEntity entity = response.getEntity();
                }finally {
                    response.close();
                }
            }catch (ClientProtocolException ex){
                //处理客户端协议异常
            }catch (IOException ex){
                //处理客户端IO异常
            }
        }
    }
}
公開された134元の記事 ウォン称賛91 ビュー160 000 +

おすすめ

転載: blog.csdn.net/weixin_44588495/article/details/102930690