Article From:https://www.cnblogs.com/mumuxinfei/p/9122421.html

 

Preface:

  httpclient(4.5.x)The default is to start the connection pool, which reduces time consumption (avoiding the first 3 handshakes, and closes the 4 handshake), significantly improves the high concurrency processing capability (a large amount of time_wait), and does play an important role. But encapsulating httpclient requiresLearn a lot of details, and configure parameters reasonably according to business.
  This is a combination of this time in depth httpclient (4.5.x) source analysis, the combination of online code cases, and the results of offline testing. Try to write an available httpclient package class, both performance and friendly interface. Thanks to CCTV, ^So.

 

Related articles:

  1. HttpClientAn in-depth analysis of the official sample code (the connection pool)

 

Version 1:

  Nothing to say, the direct code.

public class PooledHttpClientAdaptor {

    private static final int DEFAULT_POOL_MAX_TOTAL = 200;
    private static final int DEFAULT_POOL_MAX_PER_ROUTE = 200;

    private static final int DEFAULT_CONNECT_TIMEOUT = 500;
    private static final int DEFAULT_CONNECT_REQUEST_TIMEOUT = 500;
    private static final int DEFAULT_SOCKET_TIMEOUT = 2000;

    private PoolingHttpClientConnectionManager gcm = null;
    private CloseableHttpClient httpClient = null;

    // The maximum number of connections in the connection poolPrivate Final int maxTotal;The maximum number of connections configured by route / / / connection poolPrivate Final int maxPerRoute;Timeout time of / / TCP connectPrivate Final int connectTimeout;/ / get the timeout time from the connection poolPrivate fiNal int connectRequestTimeout;Read and write timeout time for / / TCP IOPrivate Final int socketTimeout;PublicPooledHttpClientAdaptor () {This (PooledHttpClientAdaptor.DEFAULT_POOL_MAX_TOTAL,PooledHttpClientAdaptor.DEFAULT_POOL_MAX_PER_ROUTE,PooledHttPClientAdaptor.DEFAULT_CONNECT_TIMEOUT,PooledHttpClientAdaptor.DEFAULT_CONNECT_REQUEST_TIMEOUT,PooledHttpClientAdaptor.DEFAULT_SOCKET_TIMEOUT);}PuBlic PooledHttpClientAdaptor (Int maxTotal,Int maxPerRoute,IntConnectTimeout,Int connectRequestTimeout,Int socketTimeout) {This.maxTotal = maxTotal;This.maxPerRoute = maxPerRoute;This.connectTimeout = COnnectTimeout;This.connectRequestTimeout = connectRequestTimeout;This.socketTimeouT = socketTimeout;Registry< ConnectionSocketFactory> registry = RegistryBuilder.< COnnectionSocketFactory> create ().register ("HTTP", PlainConnectionSocketFactory.geTSocketFactory ()).register ("HTTPS", SSLConnectionSocketFactory.getSocketFactory ()).build ();GCM = new PoolingHttpClientConnectionManager (Registry);GCm.setMaxTotal (this.maxTotal);Gcm.setDefaultMaxPerRoute (this.maxPerRoute);RequestConfig requestConfig = RequestConfig.custom ().setConnectTimeout (this.connectTimeout/ / set the connection timeout.setSocketTimeout (this.socketTimeout)/ / set read timeout.setConnectionRequestTimeout (this.connectRequestTimeout) / / set fromThe connection pool gets the timeout of the connection instance.build ();HttpClientBuilder httpClientBuilder = HttpClients.cuStom ();HttpClient = httpClientBuilder.setConnectionManager (GCM).setDefaultRequestConfig (requestConfig).build ();}Public String doGET (String URL) {Return this.doGet (URL, Collections.EMPTY_MAP, Collections.EMPTY_MAP);}Public String doGet (String URL, Map< String, Object> params) {Return this.doGet (URL, Collections.EMPTY_MAP, params);}Public String doGet (String URL,Map< String, String> headers,Map< String, Object> params) {/ / *) build the GET request headerString apiUrl = getUrlWithParams (URL, params);HttpGet HTtpGet = new HttpGet (apiUrl);/ / *) set header informationIf (headers! = null & & head)Ers.size () > 0) {For (Map.Entry< String, String> entry: headers.entrySet ()) {HttpGet.addHeader (entry.getKey (), entry.getValue ());}}CloseableHttpResponse response = null;Try {Response = httpClient.execute (HTTpGet);If (response = = null, response.getStatusLine () = = null) {RetuRN null;}Int statusCode = response.getStatusLine ().GetStatusCode ();If (statusCode = = HttpStatus.SC_OK) {HttpEntity entityRes = response.getEnTity ();If (entityRes! = null) {Return EntityUtils.toString (ENTItyRes, "UTF-8");}}Return null;} catch (IOExceptIon E) {} finally {If (response! = null) {Try {Response.close ();} catch (IOException E) {}}}Return null;}Public String doPost (String apiUrl, Map< String, Objec)T> params) {Return this.doPost (apiUrl, Collections.EMPTY_MAP, params);}PublicString doPost (String apiUrl,Map< String, String> headers,Map< String, Object> params) {HttpPost httpPost = new HttpPost (APIUrl);/ / *) configuration request headersIf (headers = null & & headers.size () > 0) {For (Map.Entry< String, String> entry: headers.entrySet ()) {HttpPOst.addHeader (entry.getKey (), entry.getValue ());}}/ / *) configuration request parametersIf (params = null & & params.size () > 0) {HttpEntity entityReq = getUrlEncodedFormEntity (params);HttpPost.setEntity (entityReq);}CloseableHTtpResponse response = null;Try {Response = httpClient.execute (httpPost);If (response = = null, response.getStatusLine () = = null) {Return null;}Int statusCode = response.getStatusLine ().GetStatusCode ();If (StatusCode = = = HttpStatus.SC_OK) {HttpEntity entityRes = response.getEntity ();If (entityRes! = null) {Return EntityUtils.toString (entityRes, "U"TF-8 ");}}Return null;} catch (IOException E) {} finally {If (response! = null) {Try {ResPonse.close ();} catch (IOException E) {}}}Return null;}Private HttpEntity getUrlEncodedFormEntity (Map< String, Object>Params) {List< NameValuePair> pairList = new ArrayList< NameValuePair> (params.si)Ze ());For (Map.Entry< String, Object> entry: params.entrySet ()) {NameValUePair pair = new BasicNameValuePair (entry.getKey ()), entry.getValue ().ToString ()))PairList.add (pair);}Return new UrlEncodedFormEntity (pairList, Char)Set.forName ("UTF-8"));}Private String getUrlWithParams (String URL, Map< String, Object&)Gt; params) {Boolean first = true;StringBuilder sb = new StringBuilder (URL);For (String key: params.keySet ()) {Char ch ='& ';If (first = = true)) {Ch = '?';First = false;}String value= params.get (key).ToString ();Try {String sval = URLEncoder.encode (valuE, "UTF-8");Sb.append (CH).Append (key).Append ("=").Append (sval);} catch(UnsupportedEncodingException E) {}}Return sb.toString ();}}

 

Existence problem & solution

  This version is basically not a problem, but when the traffic is 0, you will find a connection in the ClOSE_WAIT. The reason is that httpclient clean up the overdue / passively closed socket,A strategy of laziness cleaning. It detects and handles the state when the connection is used from the connection pool. If there is no traffic, the socket will always be in a CLOSE_WAIT (semi connected state), and the system resources are wasted.
  But the solution is quite simple, and the official recommendation is to introduce one.Cleaning thread, Periodically take the initiative to process out of time / idle connections, so that’s OK.

    private class IdleConnectionMonitorThread extends Thread {

        private final HttpClientConnectionManager connMgr;
        private volatile boolean exitFlag = false;

        public IdleConnectionMonitorThread(HttpClientConnectionManager connMgr) {
            this.connMgr = connMgr;
            setDaemon(true);
        }

        @Override
        public void run() {
            while (!this.exitFlag) {
                synchronized (this) {
                    try {
                        this.wait(2000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                // Closing the failed connectionConnMgr.closeExpiredConnections ();/ / optional, close the inactive connection in 30 secondsConnMgr.closeIdleConnections (30, TimeUnit.SECONDS);}}PubLIC void shutdown () {This.exitFlag = true;Synchronized (this) {Notify ();}}}

  

Final version

  Direct integration of code.

public class PooledHttpClientAdaptor {

    private static final int DEFAULT_POOL_MAX_TOTAL = 200;
    private static final int DEFAULT_POOL_MAX_PER_ROUTE = 200;

    private static final int DEFAULT_CONNECT_TIMEOUT = 500;
    private static final int DEFAULT_CONNECT_REQUEST_TIMEOUT = 500;
    private static final int DEFAULT_SOCKET_TIMEOUT = 2000;

    private PoolingHttpClientConnectionManager gcm = null;

    private CloseableHttpClient httpClient = null;

    private IdleConnectionMonitorThread idleThread = null;

    // The maximum number of connections in the connection poolPrivate Final int maxTotal;The maximum number of connections configured by route / / / connection poolPrivate Final int maxPerRoute;Timeout time of / / TCP connectPrivate Final int connectTimeout;/ / get the timeout time from the connection poolPrivate fiNal int connectRequestTimeout;Read and write timeout time for / / TCP IOPrivate Final int socketTimeout;PublicPooledHttpClientAdaptor () {This (PooledHttpClientAdaptor.DEFAULT_POOL_MAX_TOTAL,PooledHttpClientAdaptor.DEFAULT_POOL_MAX_PER_ROUTE,PooledHttPClientAdaptor.DEFAULT_CONNECT_TIMEOUT,PooledHttpClientAdaptor.DEFAULT_CONNECT_REQUEST_TIMEOUT,PooledHttpClientAdaptor.DEFAULT_SOCKET_TIMEOUT);}PuBlic PooledHttpClientAdaptor (Int maxTotal,Int maxPerRoute,IntConnectTimeout,Int connectRequestTimeout,Int socketTimeout) {This.maxTotal = maxTotal;This.maxPerRoute = maxPerRoute;This.connectTimeout = COnnectTimeout;This.connectRequestTimeout = connectRequestTimeout;This.socketTimeouT = socketTimeout;Registry< ConnectionSocketFactory> registry = RegistryBuilder.< COnnectionSocketFactory> create ().register ("HTTP", PlainConnectionSocketFactory.geTSocketFactory ()).register ("HTTPS", SSLConnectionSocketFactory.getSocketFactory ()).build ();This.gcm = new PoolingHttpClientConnectionManager (Registry);This.gcm.setMaxTotal (this.maxTotal);This.gcm.setDefaultMaxPerRoute (this.maxPerRoute);RequestConfig requestConfig = RequestConfig.custom ().setConnectTimeout (this.connectTimeout) / / set the connection timeout..setSocketTimeout (this.socketTimeout)/ / set read timeout.setConnectionRequestTimeout (this.connectRequestTim)Eout / / set timeout for connection instance from connection pool.build ();HttpClientBuilder httpClientBuilder =HttpClients.custom ();HttpClient = httpClientBuilder.setConnectionManager (This.gcm).setDefaultRequestConfig (requestConfig).build ();IdleThread = new IdleConnectionMonitorThread (this.gcm);IdleThread.start ();}PubLIC String doGet (String URL) {Return this.doGet (URL, Collections.EMPTY_MAP, Collections.EMP)TY_MAP);}Public String doGet (String URL, Map< String, Object> params) {RetuRN this.doGet (URL, Collections.EMPTY_MAP, params);}Public String doGet (String URL,Map< String, String> headers,Map< String, Object&gT; params) {/ / *) build the GET request headerString apiUrl = getUrlWithParams (URL, params);HttpGet httpGet = new HttpGet (apiUrl);/ / *) set header informationIf (headers! = null &Amp; & headers.size () > 0) {For (Map.Entry< String, String> entry: headers).entrySet ()) {HttpGet.addHeader (entry.getKey (), entry.getValue ());}}CloseableHttpResponse response = null;Try {Response = httpCliEnt.execute (httpGet);If (response = = null, response.getStatusLine () = = null) {Return null;}Int statusCode = response.getStatusLine ().GetStatuSCode ();If (statusCode = = HttpStatus.SC_OK) {HttpEntity entityRes =Response.getEntity ();If (entityRes! = null) {Return EntityUtilS.toString (entityRes, "UTF-8");}}Return null;} CAtch (IOException E) {} finally {If (response! = null) {Try{Response.close ();} catch (IOException E) {}}}Return null;}Public String doPost (String apiUrl, Map<String, Object> params) {Return this.doPost (apiUrl, Collections.EMPTY_MAP, params);}Public String doPost (String apiUrl,Map< String, String> headerS,Map< String, Object> params) {HttpPost httpPost = neW HttpPost (apiUrl);/ / *) configuration request headersIf (headers! = null & & headers.size)) > 0) {For (Map.Entry< String, String> entry: headers.entrySet ()) {HttpPost.addHeader (entry.getKey (), entry.getValue ());}}/ / *)Configuring request parametersIf (params = null & & params.size () > 0) {HttpEntity entitYReq = getUrlEncodedFormEntity (params);HttpPost.setEntity (entityReq);}CloseableHttpResponse response = null;Try {Response = httpClient.execute (HTTpPost);If (response = = null, response.getStatusLine () = = null) {RetUrn null;}Int statusCode = response.getStatusLine ().GetStatusCode ();If (statusCode = = HttpStatus.SC_OK) {HttpEntity entityRes = response.getENtity ();If (entityRes! = null) {Return EntityUtils.toString (EntityRes, "UTF-8");}}Return null;} catch (IOExcEption E) {} finally {If (response! = null) {Try {Response.close ();} catch (IOException E) {}}}Return null;}Private HttpEntity getUrlEncodedFormEntity (Map< Strin)G, Object> params) {List< NameValuePair> pairList = new ArrayList< NameValuePair≫ (params.size ());For (Map.Entry< String, Object> entry: params.entrySet ()) {NameValuePair pair = new BasicNameValuePair (entry.getKey ()), entry.getValuE ().ToString ()));PairList.add (pair);}Return new UrlEncodedFormEntity (PAirList, Charset.forName ("UTF-8"));}Private String getUrlWithParams (String URL, Map< St)Ring, Object> params) {Boolean first = true;StringBuilder sb = new StringBuildeR (URL);For (String key: params.keySet ()) {Char ch ='& ';If (First = = = true) {Ch = '?';First = false;}String value = params.get (key).ToString ();Try {String sval = URLEncodeR.encode (value, "UTF-8");Sb.append (CH).Append (key).Append ("=").Append (sval);} catch (UnsupportedEncodingException E) {}}Return sb.toString ();}Public void shutdown () {IdleThread.shutdown ();}/ / / monitor with abnormal linksPRIvate class IdleConnectionMonitorThread extends Thread {Private final HttpClientConnectionManager connMgr;Private volatile Boolean exitFlag = false;Public IdleConnectionMoNitorThread (HttpClientConnectionManager connMgr) {This.connMgr = connMgr;SEtDaemon (true);}@OverridePublic void run () {While (! This.ex)ItFlag) {Synchronized (this) {Try {ThIs.wait (2000);} catch (InterruptedException E) {E.prinTStackTrace ();}}/ / close a failed connectionCoNnMgr.closeExpiredConnections ();/ / optional, close the inactive connection in 30 secondsConnMgr.closeIDleConnections (30, TimeUnit.SECONDS);}}Public void shutdown () {This.exitFlag = true;Synchronized (this) {Notify ();}}}}

 

Summary:

  In fact, nothing can be done. It is mainly to buy a reassurance, so writing is safe and can stand the test on line.

  

Leave a Reply

Your email address will not be published. Required fields are marked *