1. 程式人生 > >httpcomponents httpclient連線池實現與測試

httpcomponents httpclient連線池實現與測試

在windows環境下,使用Process Explorer檢視連線數和連線狀態。

package http.connectionPool;

import org.apache.http.HeaderElement;
import org.apache.http.HeaderElementIterator;
import org.apache.http.HttpResponse;
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.config.SocketConfig;
import org.apache.http.conn.ConnectionKeepAliveStrategy;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.DefaultClientConnectionReuseStrategy;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicHeaderElementIterator;
import org.apache.http.protocol.HTTP;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.EntityUtils;

import java.io.IOException;
import java.util.Random;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;


public class TestConnectionPool {
    private static CloseableHttpClient httpClient;
    private static ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
    private static PoolingHttpClientConnectionManager cm;
    static{
        cm = new PoolingHttpClientConnectionManager();
        cm.setMaxTotal(100);
        cm.setDefaultMaxPerRoute(100);
        SocketConfig socketConfig = SocketConfig.custom()
                .setTcpNoDelay(true)     //是否立即傳送資料,設定為true會關閉Socket緩衝,預設為false
                .setSoReuseAddress(true) //是否可以在一個程序關閉Socket後,即使它還沒有釋放埠,其它程序還可以立即重用埠
                .setSoTimeout(5000)       //接收資料的等待超時時間,單位ms
                .setSoLinger(60)         //關閉Socket時,要麼傳送完所有資料,要麼等待60s後,就關閉連線,此時socket.close()是阻塞的
                .setSoKeepAlive(true)    //開啟監視TCP連線是否有效
                .build();
        cm.setDefaultSocketConfig(socketConfig);
        ConnectionKeepAliveStrategy myStrategy = new ConnectionKeepAliveStrategy() {
            public long getKeepAliveDuration(HttpResponse response, HttpContext context) {
                // Honor 'keep-alive' header
                HeaderElementIterator it = new BasicHeaderElementIterator(
                        response.headerIterator(HTTP.CONN_KEEP_ALIVE));
                while (it.hasNext()) {
                    HeaderElement he = it.nextElement();
                    String param = he.getName();
                    String value = he.getValue();
                    if (value != null && param.equalsIgnoreCase("timeout")) {
                        try {
                            return Long.parseLong(value) * 1000;
                        } catch(NumberFormatException ignore) {
                        }
                    }
                }
                return 10 * 1000;
            }
        };
        httpClient = HttpClients.custom().setConnectionManager(cm)
                .setKeepAliveStrategy(myStrategy)
                .evictExpiredConnections()
                .evictIdleConnections(30,TimeUnit.SECONDS)
                .setConnectionReuseStrategy(DefaultClientConnectionReuseStrategy.INSTANCE)
                .build();
        //定時列印連線池狀態
        executorService.scheduleAtFixedRate(() -> {
            System.out.println(cm.getTotalStats());
        },100L,1000L, TimeUnit.MILLISECONDS);
    }
    //測試
    public static void main(String[] args) {
        Random r = new Random();
        for(int i = 0;i<100000;i++){
            int n = r.nextInt(5);
            for(int t = 0;t<n;t++){
                new Thread(()->{
                    HttpGet get = new HttpGet("https://sales.test.cn/group/products?id=22");
                    HttpContext context = HttpClientContext.create();
                    CloseableHttpResponse response = null;
                    try{
                        response = httpClient.execute(get, context);
                        //一定有這行程式碼,這行觸發歸還連線到連線池
                        EntityUtils.consume(response.getEntity());
                    } catch (Exception e){
                        e.printStackTrace();
                    } finally {
                        if(response!=null){
                            try {
                                response.close();
                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                }).start();
            }
            try {
                Thread.sleep(200L);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

使用jdk自帶工具jps檢視程序號,然後在Process Explorer中檢視