程式扎記: [ Java 文章收集 ] HttpClient4.2.X 升級入門+ http連接池使用

標籤

2013年7月14日 星期日

[ Java 文章收集 ] HttpClient4.2.X 升級入門+ http連接池使用

來源自 這裡
Preface:
在一次服務器異常的排查過程當中,我們決定使用HttpClient4.X替代HttpClient3.X或者HttpConnection。為什麼使用HttpClient4?主要是HttpConnection沒有連接池的概念,多少次請求就會建立多少個IO,在訪問量巨大的情況下服務器的IO可能會耗盡。HttpClient3 也有連接池的東西在裡頭,使用 MultiThreadedHttpConnectionManager,大致過程如下:
  1. MultiThreadedHttpConnectionManager connectionManager =  new  MultiThreadedHttpConnectionManager();    
  2. HttpClient client =  new  HttpClient(connectionManager);... //在某個線程中。    
  3. GetMethod get =  new  GetMethod( "http://jakarta.apache.org/" );    
  4. try  {    
  5.     client.executeMethod(get); // print response to stdout    
  6.     System.out.println(get.getResponseBodyAsStream());    
  7. }  finally  {    
  8.     // be sure the connection is released back to the connection     
  9.     managerget.releaseConnection();    
  10. }   
可以看出來,它的方式與jdbc連接池的使用方式相近,這裡比較麻煩的就是需要手動調用 releaseConnection 去釋放連接。對每一個 HttpClient.executeMethod 須有一個 method.releaseConnection() 與之匹配!

HttpClient4.x 連接池:
這裡使用4.2.x的版本實現了一個簡單的 HttpConnectionManager,代碼如下:
  1. package nlg.utils;  
  2.   
  3. import org.apache.http.client.HttpClient;  
  4. import org.apache.http.impl.client.DefaultHttpClient;  
  5. import org.apache.http.impl.conn.PoolingClientConnectionManager;  
  6. import org.apache.http.params.BasicHttpParams;  
  7. import org.apache.http.params.HttpConnectionParams;  
  8. import org.apache.http.params.HttpParams;  
  9.   
  10. public class HttpConnectionManager {  
  11.     private static HttpParams httpParams;  
  12.     private static PoolingClientConnectionManager connectionManager;  
  13.   
  14.     /** 
  15.      * 最大连接数 
  16.      */  
  17.     public final static int MAX_TOTAL_CONNECTIONS = 2000;  
  18.   
  19.     /** 
  20.      * 每个路由最大连接数 
  21.      */  
  22.     public final static int MAX_ROUTE_CONNECTIONS = 400;  
  23.     /** 
  24.      * 连接超时时间 
  25.      */  
  26.     public final static int CONNECT_TIMEOUT = 10000;  
  27.     /** 
  28.      * 读取超时时间 
  29.      */  
  30.     public final static int READ_TIMEOUT = 10000;  
  31.   
  32.     static {          
  33.         httpParams = new BasicHttpParams();   
  34.         HttpConnectionParams.setConnectionTimeout(httpParams, CONNECT_TIMEOUT);  
  35.         HttpConnectionParams.setSoTimeout(httpParams, READ_TIMEOUT);          
  36.           
  37.         connectionManager = new PoolingClientConnectionManager();  
  38.         connectionManager.setMaxTotal(MAX_TOTAL_CONNECTIONS);  
  39.         connectionManager.setDefaultMaxPerRoute(MAX_ROUTE_CONNECTIONS);  
  40.     }  
  41.   
  42.     public static HttpClient GetHttpClient() {  
  43.         return new DefaultHttpClient(connectionManager, httpParams);  
  44.     }  
  45.   
  46.     public static synchronized void Shutdown()  
  47.     {  
  48.         if(DHC!=null)  
  49.         {  
  50.             DHC.getConnectionManager().shutdown();  
  51.             DHC = null;  
  52.         }  
  53.     }  
  54. }  
接著便可以如下使用上面建立的類別. 另外 HttpClient4 使用我們常用的 InputStream.close() 來確認連接關閉(4.1版本之前使用entity.consumeContent()來確認內容已經被消耗關閉連接):
  1. package nlg.test;  
  2.   
  3. import nlg.utils.HttpConnectionManager;  
  4.   
  5. import org.apache.http.HttpEntity;  
  6. import org.apache.http.HttpResponse;  
  7. import org.apache.http.client.HttpClient;  
  8. import org.apache.http.client.methods.HttpGet;  
  9. import org.apache.http.protocol.BasicHttpContext;  
  10. import org.apache.http.protocol.HttpContext;  
  11. import org.apache.http.util.EntityUtils;  
  12.   
  13. public class ClientMultiThreadedEx {  
  14.     public static void main(String args[]) throws Exception  
  15.     {  
  16.         try {  
  17.             // create an array of URIs to perform GETs on  
  18.             String[] urisToGet = {  
  19.                 "http://hc.apache.org/",  
  20.                 "http://hc.apache.org/httpcomponents-core-ga/",  
  21.                 "http://hc.apache.org/httpcomponents-client-ga/",  
  22.                 "http://svn.apache.org/viewvc/httpcomponents/"  
  23.             };  
  24.   
  25.             // create a thread for each URI  
  26.             GetThread[] threads = new GetThread[urisToGet.length];  
  27.             for (int i = 0; i < threads.length; i++) {  
  28.                 HttpGet httpget = new HttpGet(urisToGet[i]);  
  29.                 threads[i] = new GetThread(HttpConnectionManager.getHttpClient(), httpget, i + 1);  
  30.             }  
  31.   
  32.             // start the threads  
  33.             for (int j = 0; j < threads.length; j++) {  
  34.                 threads[j].start();  
  35.             }  
  36.   
  37.             // join the threads  
  38.             for (int j = 0; j < threads.length; j++) {  
  39.                 threads[j].join();  
  40.             }  
  41.   
  42.         } finally {  
  43.             // When HttpClient instance is no longer needed,  
  44.             // shut down the connection manager to ensure  
  45.             // immediate deallocation of all system resources  
  46.             HttpConnectionManager.Shutdown();  
  47.         }  
  48.     }  
  49.       
  50.       
  51.     /** 
  52.      * A thread that performs a GET. 
  53.      */  
  54.     static class GetThread extends Thread {  
  55.   
  56.         private final HttpClient httpClient;  
  57.         private final HttpContext context;  
  58.         private final HttpGet httpget;  
  59.         private final int id;  
  60.   
  61.         public GetThread(HttpClient httpClient, HttpGet httpget, int id) {  
  62.             this.httpClient = httpClient;  
  63.             this.context = new BasicHttpContext();  
  64.             this.httpget = httpget;  
  65.             this.id = id;  
  66.         }  
  67.   
  68.         /** 
  69.          * Executes the GetMethod and prints some status information. 
  70.          */  
  71.         @Override  
  72.         public void run() {  
  73.   
  74.             System.out.println(id + " - about to get something from " + httpget.getURI());  
  75.   
  76.             try {  
  77.   
  78.                 // execute the method  
  79.                 HttpResponse response = httpClient.execute(httpget, context);  
  80.   
  81.                 System.out.println(id + " - get executed");  
  82.                 // get the response body as an array of bytes  
  83.                 HttpEntity entity = response.getEntity();  
  84.                 if (entity != null) {  
  85.                     byte[] bytes = EntityUtils.toByteArray(entity);  
  86.                     System.out.println(id + " - " + bytes.length + " bytes read");  
  87.                 }  
  88.   
  89.             } catch (Exception e) {  
  90.                 httpget.abort();  
  91.                 System.out.println(id + " - error: " + e);  
  92.             }  
  93.         }  
  94.   
  95.     }  
  96. }  
Supplement:
HttpClient 3.1 Threading issue
Class PoolingClientConnectionManager
Manages a pool of client connections and is able to service connection requests from multiple execution threads. Connections are pooled on a per route basis. A request for a route which already the manager has persistent connections for available in the pool will be services by leasing a connection from the pool rather than creating a brand new connection.

This message was edited 9 times. Last update was at 14/07/2013 16:08:34

沒有留言:

張貼留言

網誌存檔

關於我自己

我的相片
Where there is a will, there is a way!