HttpClient的连接池
2016-08-16 11:12
483 查看
写在前面
HttpClient相比传统JDK自带的URLConnection,增加了易用性和灵活性,它不仅是客户端发送Http请求变得容易,而且也方便了开发人员测试接口(基于Http协议的),即提高了开发的效率,也方便提高代码的健壮性。一、为什么要用Http连接池
1、降低延迟:如果不采用连接池,每次连接发起Http请求的时候都会重新建立TCP连接(经历3次握手),用完就会关闭连接(4次挥手)。2、支持更大的并发:如果不采用连接池,每次连接都会打开一个端口,在大并发的情况下系统的端口资源很快就会被用完,导致无法建立新的连接。
二、具体实现
httpclient4.3之后就推荐使用连接池的方式了。package com.icekredit.credit.common.utils; import net.sf.json.JSONObject; import org.apache.http.HttpEntity; import org.apache.http.NameValuePair; import org.apache.http.client.config.RequestConfig; import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; 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.LayeredConnectionSocketFactory; import org.apache.http.conn.socket.PlainConnectionSocketFactory; import org.apache.http.conn.ssl.SSLConnectionSocketFactory; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; import org.apache.http.message.BasicNameValuePair; import org.apache.http.ssl.SSLContextBuilder; import org.apache.http.ssl.TrustStrategy; import org.apache.http.util.EntityUtils; import javax.net.ssl.SSLContext; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.net.MalformedURLException; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import java.security.KeyManagementException; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Set; /** * Class 提高并发数,减少握手次数,httpclient的连接池 * * @author hua xu * @version 1.0.0 * @date 16/08/15 */ public class HttpUtils { private static String NULL_URL = "url is null!"; private static String ERROR_TYPE = "method is not support!"; // 类初始化时,自动实例化,饿汉单例模式 private static final HttpUtils httpUtils = new HttpUtils(); // 创建httpclient连接池 private PoolingHttpClientConnectionManager httpClientConnectionManager = null; // 单例的静态方法,返回HttpUtils的实例 public static HttpUtils getHttpUtils() { return httpUtils; } // 私有的构造函数 private HttpUtils() { initHttpClient(); } /** * 发送请求 * * @param method 请求方法 * @param urlString url * @param jsonObject json * @return * @throws URISyntaxException */ public static String httpRequest(String method, String urlString, JSONObject jsonObject) throws URISyntaxException, MalformedURLException { if (StringUtils.isEmpty(urlString)) { return NULL_URL; } else { urlString = urlString.trim(); URL url = new URL(urlString); URI uri = new URI(url.getProtocol(), url.getHost(), url.getPath(), url.getQuery(), null); CloseableHttpClient httpClient = null; if (urlString.startsWith("https")) { httpClient = getSSLHttpClient(); } else { httpClient = httpUtils.getHttpClient(); } CloseableHttpResponse response = null; String json = null; switch (method) { case "GET": { HttpGet http = new HttpGet(uri); try { response = httpClient.execute(http); HttpEntity entity = response.getEntity(); json = EntityUtils.toString(entity, "utf-8"); EntityUtils.consume(entity); return json; } catch (UnsupportedOperationException | IOException e) { e.printStackTrace(); } finally { if (response != null) { try { response.close(); } catch (IOException e) { e.printStackTrace(); } } http.releaseConnection(); } } case "POST": { HttpPost http = new HttpPost(uri); try { StringEntity entity = new StringEntity(jsonObject.toString(), "utf-8"); // 解决中文乱码问题 entity.setContentEncoding("UTF-8"); entity.setContentType("application/json"); http.setEntity(entity); response = httpClient.execute(http); HttpEntity httpEntity = response.getEntity(); json = EntityUtils.toString(httpEntity, "utf-8"); EntityUtils.consume(entity); return json; } catch (IOException e) { e.printStackTrace(); } finally { if (response != null) { < d66b span class="hljs-keyword">try { response.close(); } catch (IOException e) { e.printStackTrace(); } } http.releaseConnection(); } } default: return ERROR_TYPE; } } } /** * 发送请求 * * @param urlString url * @param params 发送map * @return * @throws MalformedURLException * @throws URISyntaxException */ public static String httpRequest(String urlString, Map<String, Object> params) throws MalformedURLException, URISyntaxException { if (StringUtils.isEmpty(urlString)) { return NULL_URL; } else { urlString = urlString.trim(); URL url = new URL(urlString); URI uri = new URI(url.getProtocol(), url.getHost(), url.getPath(), url.getQuery(), null); CloseableHttpClient httpClient = null; if (urlString.startsWith("https")) { httpClient = getSSLHttpClient(); } else { httpClient = httpUtils.getHttpClient(); } CloseableHttpResponse response = null; String json = null; HttpPost http = new HttpPost(uri); try { setPostParams(http, params); response = httpClient.execute(http); HttpEntity httpEntity = response.getEntity(); json = EntityUtils.toString(httpEntity, "utf-8"); EntityUtils.consume(httpEntity); return json; } catch (IOException e) { e.printStackTrace(); } finally { if (response != null) { try { response.close(); } catch (IOException e) { e.printStackTrace(); } } http.releaseConnection(); } return json; } } private static void setPostParams(HttpPost httpost, Map<String, Object> params) { List<NameValuePair> nvps = new ArrayList<NameValuePair>(); Set<String> keySet = params.keySet(); for (String key : keySet) { nvps.add(new BasicNameValuePair(key, params.get(key).toString())); } try { httpost.setEntity(new UrlEncodedFormEntity(nvps, "UTF-8")); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } } /** * 创建httpclient连接池,并初始化httpclient */ public void initHttpClient() { LayeredConnectionSocketFactory ssl_sf = null; try { ssl_sf = new SSLConnectionSocketFactory(SSLContext.getDefault()); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create() .register("https", ssl_sf) .register("http", new PlainConnectionSocketFactory()) .build(); // 创建httpclient连接池 httpClientConnectionManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry); // 设置连接池最大数量 httpClientConnectionManager.setMaxTotal(200); // 设置单个路由最大连接数量 httpClientConnectionManager.setDefaultMaxPerRoute(20); } /** * 多线程调用时,需要创建自己的httpclient * * @return */ public CloseableHttpClient getHttpClient() { RequestConfig requestConfig = RequestConfig.custom() .setConnectTimeout(60000) .setSocketTimeout(60000).build(); CloseableHttpClient httpClient = HttpClients.custom().setConnectionManager(httpClientConnectionManager) .setDefaultRequestConfig(requestConfig).build(); /* CloseableHttpClient httpClient = HttpClients.createDefault();//如果不采用连接池就是这种方式获取连接 */ return httpClient; } /** * 针对https采用SSL的方式创建httpclient * * @return */ public static CloseableHttpClient getSSLHttpClient() { try { SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() { //信任所有 public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException { return true; } }).build(); SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext); return HttpClients.custom().setSSLSocketFactory(sslsf).build(); } catch (KeyManagementException e) { e.printStackTrace(); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (KeyStoreException e) { e.printStackTrace(); } return HttpClients.createDefault(); } } //~ Formatted by Jindent --- http://www.jindent.com
参考链接
HttpClient4.5.2 连接池原理及注意事项
HttpClient使用详解
HttpClient4.3教程 第二章 连接管理
Http请求连接池 - HttpClient 连接池
相关文章推荐
- httpclient4.2.1最新版连接池配置
- 配置使用连接池的httpClient
- 一个TCP连接池的自我修养-如mysql-client、http-client、redis-client
- HttpClient 4.3连接池参数配置及源码解读
- httpclient http连接池 源码阅读
- HttpClient4.X 升级 入门 + http连接池使用
- httpclient4.2.1最新版连接池配置
- HttpClient连接池抛出大量ConnectionPoolTimeoutException: Timeout waiting for connection
- Http请求连接池 - HttpClient 的 PoolingHttpClientConnectionManager
- Http请求连接池 - HttpClient 的 PoolingHttpClientConnectionManager
- HttpClient连接池抛出大量ConnectionPoolTimeoutException: Timeout waiting for connection异常排查
- HttpClient连接池原理及一次连接时序图
- 使用HttpClient的PoolingHttpClientConnectionManager实现Http请求连接池
- HttpAsyncClient的连接池使用
- HttpClient4.X 升级 入门 + http连接池使用-too many open files
- 一个TCP连接池的自我修养-如mysql-client、http-client、redis-client
- Http请求连接池 - HttpClient 的 PoolingHttpClientConnectionManager
- httpClient 4.5.2 实现连接池
- HttpClient连接池抛出大量ConnectionPoolTimeoutException: Timeout waiting for connection异常排查