轻松把玩HttpClient之封装HttpClient工具类(二),插件式配置HttpClient对象

上一篇文章中,简单分享一下封装HttpClient工具类的思路及部分代码,本文将分享如何实现插件式配置HttpClient对象。


如果你看过我前面的几篇关于HttpClient的文章或者官网示例,应该都知道HttpClient对象在创建时,都可以设置各种参数,但是却没有简单的进行封装,比如对我来说比较重要的3个:代理、ssl(包含绕过证书验证和自定义证书验证)、超时。还需要自己写。所以这里我就简单封装了一下,顺便还封装了一个连接池的配置。


其实说是插件式配置,那是高大上的说法,说白了,就是采用了建造者模式来创建HttpClient对象(级联调用)。HttpClient的jar包中提供了一个创建HttpClient对象的类HttpClientBuilder。所以我是创建该类的子类HCB,然后做了一些改动。每个配置方法的返回值都是HCB,这样就支持级联调用了。具体代码如下:

[java]  view plain  copy
 print ?
  1. package com.tgb.ccl.http.httpclient.builder;  
  2.   
  3. import org.apache.http.HttpHost;  
  4. import org.apache.http.client.config.RequestConfig;  
  5. import org.apache.http.config.Registry;  
  6. import org.apache.http.config.RegistryBuilder;  
  7. import org.apache.http.conn.socket.ConnectionSocketFactory;  
  8. import org.apache.http.conn.socket.PlainConnectionSocketFactory;  
  9. import org.apache.http.impl.client.HttpClientBuilder;  
  10. import org.apache.http.impl.conn.DefaultProxyRoutePlanner;  
  11. import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;  
  12.   
  13. import com.tgb.ccl.http.common.SSLs;  
  14. import com.tgb.ccl.http.exception.HttpProcessException;  
  15.   
  16. /** 
  17.  * httpclient创建者 
  18.  *  
  19.  * @author arron 
  20.  * @date 2015年11月9日 下午5:45:47  
  21.  * @version 1.0 
  22.  */  
  23. public class  HCB extends HttpClientBuilder{  
  24.       
  25.     private boolean isSetPool=false;//记录是否设置了连接池  
  26.     private boolean isNewSSL=false;//记录是否设置了更新了ssl  
  27.       
  28.     //用于配置ssl  
  29.     private SSLs ssls = SSLs.getInstance();  
  30.       
  31.     private HCB(){}  
  32.     public static HCB custom(){  
  33.         return new HCB();  
  34.     }  
  35.   
  36.     /** 
  37.      * 设置超时时间 
  38.      *  
  39.      * @param timeout       超市时间,单位-毫秒 
  40.      * @return 
  41.      */  
  42.     public HCB timeout(int timeout){  
  43.          // 配置请求的超时设置  
  44.         RequestConfig config = RequestConfig.custom()  
  45.                 .setConnectionRequestTimeout(timeout)  
  46.                 .setConnectTimeout(timeout)  
  47.                 .setSocketTimeout(timeout)  
  48.                 .build();  
  49.         return (HCB) this.setDefaultRequestConfig(config);  
  50.     }  
  51.       
  52.     /** 
  53.      * 设置ssl安全链接 
  54.      *  
  55.      * @return 
  56.      * @throws HttpProcessException 
  57.      */  
  58.     public HCB ssl() throws HttpProcessException {  
  59.         if(isSetPool){//如果已经设置过线程池,那肯定也就是https链接了  
  60.             if(isNewSSL){  
  61.                 throw new HttpProcessException("请先设置ssl,后设置pool");  
  62.             }  
  63.             return this;  
  64.         }  
  65.         Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder  
  66.                 .<ConnectionSocketFactory> create()  
  67.                 .register("http", PlainConnectionSocketFactory.INSTANCE)  
  68.                 .register("https", ssls.getSSLCONNSF()).build();  
  69.         //设置连接池大小  
  70.         PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);  
  71.         return (HCB) this.setConnectionManager(connManager);  
  72.     }  
  73.       
  74.   
  75.     /** 
  76.      * 设置自定义sslcontext 
  77.      *  
  78.      * @param keyStorePath      密钥库路径 
  79.      * @return 
  80.      * @throws HttpProcessException 
  81.      */  
  82.     public HCB ssl(String keyStorePath) throws HttpProcessException{  
  83.         return ssl(keyStorePath,"nopassword");  
  84.     }  
  85.     /** 
  86.      * 设置自定义sslcontext 
  87.      *  
  88.      * @param keyStorePath      密钥库路径 
  89.      * @param keyStorepass      密钥库密码 
  90.      * @return 
  91.      * @throws HttpProcessException 
  92.      */  
  93.     public HCB ssl(String keyStorePath, String keyStorepass) throws HttpProcessException{  
  94.         this.ssls = SSLs.custom().customSSL(keyStorePath, keyStorepass);  
  95.         this.isNewSSL=true;  
  96.         return ssl();  
  97.     }  
  98.       
  99.       
  100.     /** 
  101.      * 设置连接池(默认开启https) 
  102.      *  
  103.      * @param maxTotal                  最大连接数 
  104.      * @param defaultMaxPerRoute    每个路由默认连接数 
  105.      * @return 
  106.      * @throws HttpProcessException 
  107.      */  
  108.     public HCB pool(int maxTotal, int defaultMaxPerRoute) throws HttpProcessException{  
  109.         Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder  
  110.                 .<ConnectionSocketFactory> create()  
  111.                 .register("http", PlainConnectionSocketFactory.INSTANCE)  
  112.                 .register("https", ssls.getSSLCONNSF()).build();  
  113.         //设置连接池大小  
  114.         PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);  
  115.         connManager.setMaxTotal(maxTotal);  
  116.         connManager.setDefaultMaxPerRoute(defaultMaxPerRoute);  
  117.         isSetPool=true;  
  118.         return (HCB) this.setConnectionManager(connManager);  
  119.     }  
  120.       
  121.     /** 
  122.      * 设置代理 
  123.      *  
  124.      * @param hostOrIP      代理host或者ip 
  125.      * @param port          代理端口 
  126.      * @return 
  127.      */  
  128.     public HCB proxy(String hostOrIP, int port){  
  129.         // 依次是代理地址,代理端口号,协议类型    
  130.         HttpHost proxy = new HttpHost(hostOrIP, port, "http");    
  131.         DefaultProxyRoutePlanner routePlanner = new DefaultProxyRoutePlanner(proxy);  
  132.         return (HCB) this.setRoutePlanner(routePlanner);  
  133.     }  
  134. }  

大家可以看到,这个有成员变量,而且不是static类型,所以是非线程安全的。所以我为了方便使用,就效仿HttpClients(其custom方法可以创建HttpClientBuilder实例)写了一个静态的custom方法,来返回一个新的HCB实例。将构造方法设置成了private,无法通过new的方式创建实例,所以只能通过custom方法来创建。在想生成HttpClient对象的时候,调用一下build方法就可以了。于是乎就出现了这样简单、方便又明了的调用方式:

[java]  view plain  copy
 print ?
  1. HttpClient client = HCB.custom().timeout(10000).proxy("127.0.0.1"8087).ssl("D:\\keys\\wsriakey","tomcat").build();  

说到ssl,还需要另外一个封装的类,为了其他工具类有可能也会用到ssl,所以就单出来了。不多解释,直接上代码:

[java]  view plain  copy
 print ?
  1. /** 
  2.  * 设置ssl 
  3.  *  
  4.  * @author arron 
  5.  * @date 2015年11月3日 下午3:11:54 
  6.  * @version 1.0 
  7.  */  
  8. public class SSLs {  
  9.   
  10.     private static final SSLHandler simpleVerifier = new SSLHandler();  
  11.     private static SSLConnectionSocketFactory sslConnFactory ;  
  12.     private static SSLs sslutil = new SSLs();  
  13.     private SSLContext sc;  
  14.       
  15.     public static SSLs getInstance(){  
  16.         return sslutil;  
  17.     }  
  18.     public static SSLs custom(){  
  19.         return new SSLs();  
  20.     }  
  21.   
  22.     // 重写X509TrustManager类的三个方法,信任服务器证书  
  23.     private static class SSLHandler implements  X509TrustManager, HostnameVerifier{  
  24.           
  25.         @Override  
  26.         public java.security.cert.X509Certificate[] getAcceptedIssuers() {  
  27.             return null;  
  28.         }  
  29.           
  30.         @Override  
  31.         public void checkServerTrusted(java.security.cert.X509Certificate[] chain,  
  32.                 String authType) throws java.security.cert.CertificateException {  
  33.         }  
  34.           
  35.         @Override  
  36.         public void checkClientTrusted(java.security.cert.X509Certificate[] chain,  
  37.                 String authType) throws java.security.cert.CertificateException {  
  38.         }  
  39.   
  40.         @Override  
  41.         public boolean verify(String paramString, SSLSession paramSSLSession) {  
  42.             return true;  
  43.         }  
  44.     };  
  45.       
  46.     // 信任主机  
  47.     public static HostnameVerifier getVerifier() {  
  48.         return simpleVerifier;  
  49.     }  
  50.       
  51.     public synchronized SSLConnectionSocketFactory getSSLCONNSF() throws HttpProcessException {  
  52.         if (sslConnFactory != null)  
  53.             return sslConnFactory;  
  54.         try {  
  55.             SSLContext sc = getSSLContext();  
  56.             sc.init(nullnew TrustManager[] { simpleVerifier }, null);  
  57.             sslConnFactory = new SSLConnectionSocketFactory(sc, simpleVerifier);  
  58.         } catch (KeyManagementException e) {  
  59.             throw new HttpProcessException(e);  
  60.         }  
  61.         return sslConnFactory;  
  62.     }  
  63.       
  64.     public SSLs customSSL(String keyStorePath, String keyStorepass) throws HttpProcessException{  
  65.         FileInputStream instream =null;  
  66.         KeyStore trustStore = null;   
  67.         try {  
  68.             trustStore = KeyStore.getInstance(KeyStore.getDefaultType());  
  69.             instream = new FileInputStream(new File(keyStorePath));  
  70.             trustStore.load(instream, keyStorepass.toCharArray());  
  71.             // 相信自己的CA和所有自签名的证书  
  72.             sc= SSLContexts.custom().loadTrustMaterial(trustStore, new TrustSelfSignedStrategy()) .build();   
  73.         } catch (KeyStoreException | NoSuchAlgorithmException | CertificateException | IOException | KeyManagementException e) {  
  74.             throw new HttpProcessException(e);  
  75.         }finally{  
  76.             try {  
  77.                 instream.close();  
  78.             } catch (IOException e) {}  
  79.         }  
  80.         return this;  
  81.     }  
  82.       
  83.     public SSLContext getSSLContext() throws HttpProcessException{  
  84.         try {  
  85.             if(sc==null){  
  86.                 sc = SSLContext.getInstance("SSLv3");  
  87.             }  
  88.             return sc;  
  89.         } catch (NoSuchAlgorithmException e) {  
  90.             throw new HttpProcessException(e);  
  91.         }  
  92.     }  
  93. }  

基本上就是这样了。在上一篇中遗留了一个小问题,正好在这里说一下。上一篇文中说道提供一个默认的HttpClient实现,其实是2个,分别针对于http和https。方便调用。具体代码如下:

[java]  view plain  copy
 print ?
  1. //默认采用的http协议的HttpClient对象  
  2. private static  HttpClient client4HTTP;  
  3.   
  4. //默认采用的https协议的HttpClient对象  
  5. private static HttpClient client4HTTPS;  
  6.   
  7. static{  
  8.     try {  
  9.         client4HTTP = HCB.custom().build();  
  10.         client4HTTPS = HCB.custom().ssl().build();  
  11.     } catch (HttpProcessException e) {  
  12.         logger.error("创建https协议的HttpClient对象出错:{}", e);  
  13.     }  
  14. }  
  15.   
  16. /** 
  17.  * 判断url是http还是https,直接返回相应的默认client对象 
  18.  *  
  19.  * @return                      返回对应默认的client对象 
  20.  * @throws HttpProcessException  
  21.  */  
  22. private static HttpClient create(String url) throws HttpProcessException  {  
  23.     if(url.toLowerCase().startsWith("https://")){  
  24.         return client4HTTPS;  
  25.     }else{  
  26.         return client4HTTP;  
  27.     }  
  28. }  
这样在使用工具类的时候,如果不需要自定义HttpClient时,就直接用下面的方式调用:
[java]  view plain  copy
 print ?
  1. public static void testSimple() throws HttpProcessException{  
  2.     String url = "http://tool.oschina.net/";  
  3.     //简单调用  
  4.     String resp = HttpClientUtil.send(url);  
  5.     System.out.println("请求结果内容长度:"+ resp);  
  6. }  

好了,插件化配置HttpClient,就是这些内容,在下一篇文章中分享如何插件式配置Header。没错,思路还是跟本文一样。敬请期待吧。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值