httpcomponents httpclient連線池實現與測試
阿新 • • 發佈:2019-05-24
在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中檢視