HttpClient4.5.2 HttpClientBuilder配置使用连接池

先看示例代码,代码有点长,不过大家理清思路来看应该不是问题:

import java.io.IOException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import org.apache.http.HttpEntity;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicHeader;
import org.apache.http.pool.PoolStats;
import org.apache.http.util.EntityUtils;

/*
 * httpclient版本: 4.5.2
 * httpclient的使用始于HttpClientBuilder
 */
public class TestHttpClientPool {
	public static void main(String[] args) throws Exception{
		HttpClientBuilder builder=HttpClientBuilder.create();
		/*一、为HttpClientBuilder设置绕过不安全的https证书
		 */
		 Registry<ConnectionSocketFactory> registry 
	       = RegistryBuilder.<ConnectionSocketFactory>create()  
	         .register("http", PlainConnectionSocketFactory.INSTANCE)  
	         .register("https", trustHttpsCertificates())  
	         .build();
		/*二、为HttpClientBuilder设置PoolingHttpClientConnectionManager
		 */
		PoolingHttpClientConnectionManager cm=new PoolingHttpClientConnectionManager(registry);
		cm.setMaxTotal(200);//维护的httpclientConnection总数
		//每一个route的最大连接数,route可以理解为一个主机,如http://www.roadjava.com/2.html
		//和http://www.roadjava.com/1.html是一个主机
		cm.setDefaultMaxPerRoute(20);
		builder.setConnectionManager(cm);
		/*三、为HttpClientBuilder设置从连接池获取连接的超时时间、连接超时时间、获取数据响应超时时间
		 */
		RequestConfig requestConfig=RequestConfig.custom().
				setConnectionRequestTimeout(5000).
				setConnectTimeout(5000).
                setSocketTimeout(5000).build();
		builder.setDefaultRequestConfig(requestConfig);
		/*
		 * 四、设置默认的header
		 */
		List<BasicHeader> basicHeaders=new ArrayList<>();
		BasicHeader basicHeader=new BasicHeader("User-Agent",
"Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.101 Safari/537.36");
		basicHeaders.add(basicHeader);
		builder.setDefaultHeaders(basicHeaders);
		
	     PoolStats totalStats = cm.getTotalStats();
         System.out.println("最大:"+totalStats.getMax());
         System.out.println("占用的:"+totalStats.getLeased());
         System.out.println("可用的:"+totalStats.getAvailable());
         for(int i=0;i<30;i++){
        	 //HttpClients.createDefault();内部调用的是HttpClientBuilder.create().build();
        	 //配置是采用的默认配置
        	 CloseableHttpClient client = builder.build();
     		
    		 String url="http://www.roadjava.com/";
             HttpGet httpGet=new HttpGet(url);
             //处理响应部分
             CloseableHttpResponse response =null;
             try {
                 response = client.execute(httpGet);
                 HttpEntity entity = response.getEntity();
//                 System.out.println("获取到的内容:"+EntityUtils.toString(entity,"UTF-8"));
                 
                 PoolStats totalStats2 = cm.getTotalStats();
                 System.out.println("最大:"+totalStats2.getMax());
                 System.out.println("占用的:"+totalStats2.getLeased());
                 System.out.println("可用的:"+totalStats2.getAvailable());
                 EntityUtils.consume(entity);//关闭entity
             } catch (Exception e) {
                 e.printStackTrace();
             } finally{
            	 //不要调用这句,如果调用了就把连接从连接池真正销毁了,连接池使用失去了意义
//                 if (client!=null) {
//                     try {client.close();} catch (IOException e) {e.printStackTrace();}
//                 }
                 if (response!=null) {
                     try {response.close();} catch (IOException e) {e.printStackTrace();}
                 }
             }
         }
		
         PoolStats totalStats3 = cm.getTotalStats();
         System.out.println("最大:"+totalStats3.getMax());
         System.out.println("占用的:"+totalStats3.getLeased());
         System.out.println("可用的:"+totalStats3.getAvailable());
	}
	 //创建并返回SSLConnectionSocketFactory对象
    public static ConnectionSocketFactory trustHttpsCertificates() throws Exception {  
        SSLConnectionSocketFactory socketFactory = null;  
        TrustManager[] trustAllCerts = new TrustManager[1];  
        TrustManager tm = new myTM();  
        trustAllCerts[0] = tm;  
        SSLContext sc = null;  
        try {  
            sc = SSLContext.getInstance("TLS");  
            sc.init(null, trustAllCerts, null);  
            socketFactory = new SSLConnectionSocketFactory(sc, NoopHostnameVerifier.INSTANCE);  
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
        return socketFactory;  
    }  
   static class myTM implements TrustManager, X509TrustManager {  
        public X509Certificate[] getAcceptedIssuers() {  
            return null;  
        }  
        public void checkServerTrusted(X509Certificate[] certs, String authType) {  
               
        }  
        public void checkClientTrusted(X509Certificate[] certs, String authType) {  
                
        }  
    }  
}

运行结果:

image.png

image.png

从httpclient使用连接池可以看到PoolingHttpClientConnectionManager之后,我们可以看到,针对同一个route,httpclient不再是每次请求都新建一个连接(httpconnection)了,而是从连接池里面找可以复用的连接,这样就省去了建立连接以及关闭连接时的耗时。

因为我设置的每个route可用的并发数是20,如果我把

EntityUtils.consume(entity);//关闭entity

以及

if (response!=null) {
 try {response.close();} catch (IOException e) {e.printStackTrace();}
}

注释掉,也就意味着,连接使用之后,并没有放到连接池的AvailableSet里面,表示这个连接一直处于占用状态,那么我们预期在请求到20次的时候它就会从连接池里面无法获取到可用连接,又因为我设置了从连接池里面获取可用连接的等待超时时间是5秒(setConnectionRequestTimeout(5000)),在等待5秒之后就应该报错,是不是这样呢?如下图,正如我们预期,报了org.apache.http.conn.ConnectionPoolTimeoutException: Timeout waiting for connection from pool这个错误:

image.png

这就是httpclient里面连接池PoolingHttpClientConnectionManager的使用方法。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值