最近使用HttpClient 4.5 使用 CloseableHttpClient 发起连接后,使用CloseableHttpResponse 接受返回结果,结果就报错了,上网查了下,有位stackoverflow的大兄弟说,只要将:

 CloseableHttpClient httpClient    = HttpClients.createDefault();
改为:
CloseableHttpClient httpClient = HttpClients.custom().setConnectionManager(connManager).setConnectionManagerShared(true).build();

就可以整正常执行了,于是,用之,果然不报错了,但是为什么呢?以下是大兄弟的原文解释:

I was having a similar error when I came across this thread and this seemed to fix the issue for me. I know this is an old question, but adding thoughts for others for future reference.

I'm not 100% sure as to why this fix works as the documentation around this is pretty awful. It was a lot of trial and error with what I was testing to get to this solution. From what I can

gather though, this fix works because it is then using a shared connection pool in the background, which means that connections remain open for use.

关键是最后一句话:大概意思是,后台使用一个共享连接池,供剩下打开的连接去使用

原文地址:https://stackoverflow.com/questions/41744410/executorservice-performing-rest-requests

感谢下这位大兄弟

apache 官方的建议是,创建连接池,并为每一个接口URL分配一个线程,去执行,还给出了许多高并发访问的编码技巧

原文:https://hc.apache.org/httpcomponents-client-ga/tutorial/html/connmgmt.html

那么,使用HttpClient 4.5连接池的正确姿势是什么呢?

原作者地址:https://my.oschina.net/xlj44400/blog/711341

摘要: HttpClient 是 Apache Jakarta Common 下的子项目,可以用来提供高效的、最新的、功能丰富的支持 HTTP 协议的客户端编程工具包,并且它支持 HTTP 协议最新的版本和建议

HttpClient简介

HttpClient 是 Apache Jakarta Common 下的子项目,可以用来提供高效的、最新的、功能丰富的支持 HTTP 协议的客户端编程工具包,并且它支持 HTTP 协议最新的版本和建议。HttpClient支持的功能如下:

  • 支持Http0.9、Http1.0和Http1.1协议。
  • 实现了Http全部的方法(GET,POST,PUT,HEAD 等)。
  • 支持HTTPS协议。
  • 支持代理服务器。
  • 提供安全认证方案。
  • 提供连接池以便重用连接。
  • 连接管理器支持多线程应用。支持设置最大连接数,同时支持设置每个主机的最大连接数,发现并关闭过期的连接。
  • 在http1.0和http1.1中利用KeepAlive保持长连接。

以前是commons-httpclient,后面被Apache HttpComponents取代,目前版本4.5.x,我们现在用的就是4.5版本

HttpClient连接池使用

为什么要用Http连接池:

1、降低延迟:如果不采用连接池,每次连接发起Http请求的时候都会重新建立TCP连接(经历3次握手),用完就会关闭连接(4次挥手),如果采用连接池则减少了这部分时间损耗

2、支持更大的并发:如果不采用连接池,每次连接都会打开一个端口,在大并发的情况下系统的端口资源很快就会被用完,导致无法建立新的连接
  • 默认http协议:
private static final Charset CHAR_SET = Charset.forName("utf-8");
private static PoolingHttpClientConnectionManager cm; public void init() {
cm = new PoolingHttpClientConnectionManager();
cm.setMaxTotal(50);
cm.setDefaultConnectionConfig(ConnectionConfig.custom()
.setCharset(CHAR_SET).build());
SocketConfig socketConfig = SocketConfig.custom().setSoTimeout(30000)
.setSoReuseAddress(true).build();
cm.setDefaultSocketConfig(socketConfig);
// HttpProtocolParams.setContentCharset(httpParams, "UTF-8");
// HttpClientParams.setCookiePolicy(httpParams, "ignoreCookies");
// HttpConnectionParams.setConnectionTimeout(httpParams, 30000);
// HttpConnectionParams.setSoTimeout(httpParams, 30000);
httpClient = HttpClientBuilder.create().setConnectionManager(cm)
.build();
} public CloseableHttpClient getHttpClient() {
int timeout=2;
RequestConfig config = RequestConfig.custom()
.setConnectTimeout(timeout * 1000) //设置连接超时时间,单位毫秒
//.setConnectionRequestTimeout(timeout * 1000) //设置从connect Manager获取Connection 超时时间,单位毫秒
.setSocketTimeout(timeout * 1000).build(); //请求获取数据的超时时间,单位毫秒
CloseableHttpClient _httpClient = HttpClients.custom()
.setConnectionManager(cm).setDefaultRequestConfig(config)
.build();
if(cm!=null&&cm.getTotalStats()!=null) { //打印连接池的状态
LOGGER.info("now client pool {}",cm.getTotalStats().toString());
}
return _httpClient;
} public String post(String url, Map<String, String> params) {
HttpPost post = new HttpPost(url);
String resp = null;
try {
if(params != null){
List<NameValuePair> nvps = new ArrayList<NameValuePair>();
for (Map.Entry<String, String> param : params.entrySet()) {
nvps.add(new BasicNameValuePair(param.getKey(), param.getValue()));
}
post.setEntity(new UrlEncodedFormEntity(nvps, CHAR_SET));
} try {
HttpResponse response = httpClient.execute(post);
InputStream input = response.getEntity().getContent();
resp = IOUtils.toString(input);
} catch (ClientProtocolException e) {
LOGGER.error(e.getMessage(), e);
} catch (IOException e) {
LOGGER.error(e.getMessage(), e);
} catch (Exception e) {
LOGGER.error(e.getMessage(), e);
}
} finally {
if (post != null)
post.releaseConnection();
}
return resp;
}
  • https协议:
public class HttpConnectionManager {

    PoolingHttpClientConnectionManager cm = null;

    public void init() {
LayeredConnectionSocketFactory sslsf = null;
try {
sslsf = new SSLConnectionSocketFactory(SSLContext.getDefault());
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory> create()
.register("https", sslsf)
.register("http", new PlainConnectionSocketFactory())
.build();
cm =new PoolingHttpClientConnectionManager(socketFactoryRegistry);
cm.setMaxTotal(200);
cm.setDefaultMaxPerRoute(20);
} public CloseableHttpClient getHttpClient() {
CloseableHttpClient httpClient = HttpClients.custom()
.setConnectionManager(cm)
.build(); /*
//如果不采用连接池就是这种方式获取连接
CloseableHttpClient httpClient = HttpClients.createDefault();
*/
return httpClient;
}
}
  • httpClient使用
catch (Exception e) {
logger.error("ufile send error e:",e);
try {
if (resEntity != null && resEntity.getContent() != null) {
resEntity.getContent().close();
}
} catch (IllegalStateException | IOException e1) {
logger.error("ufile send error e1:",e1);
} finally {
if (getMethod!=null) {
getMethod.releaseConnection();
}
/*if (httpClient!=null) { //连接池使用的时候不能关闭连接,否则下次使用会抛异常 java.lang.IllegalStateException: Connection pool shut down
try {
httpClient.close();
} catch (IOException e2) {
logger.error("ufile httpclient close error e2:",e2);
}
}*/
}
}
  • 连接池使用注意事项:
    1. 连接池中连接都是在发起请求的时候建立,并且都是长连接
    
    2. HttpResponse input.close();作用就是将用完的连接释放,下次请求可以复用,这里特别注意的是,如果不使用in.close();而仅仅使用httpClient.close();结果就是连接会被关闭,并且不能被复用,这样就失去了采用连接池的意义。
    
    3. 连接池释放连接的时候,并不会直接对TCP连接的状态有任何改变,只是维护了两个Set,leased和avaliabled,leased代表被占用的连接集合,avaliabled代表可用的连接的集合,释放连接的时候仅仅是将连接从leased中remove掉了,并把连接放到avaliabled集合中

打印的状态:

INFO c.m.p.u.h.HttpClientUtils[72] - now client pool [leased: 0; pending: 0; available: 0; max: 50]

leased :the number of persistent connections tracked by the connection manager currently being used to execute requests.  

available :the number idle persistent connections.  

pending : the number of connection requests being blocked awaiting a free connection.  

max: the maximum number of allowed persistent connections.

HttpClient 4.5超时设置

4.5版本中,这两个参数的设置都抽象到了RequestConfig中,由相应的Builder构建,具体的例子如下:

CloseableHttpClient httpclient = HttpClients.createDefault();
HttpGet httpGet = new HttpGet("http://stackoverflow.com/");
RequestConfig requestConfig = RequestConfig.custom()
.setConnectTimeout(5000).setConnectionRequestTimeout(1000)
.setSocketTimeout(5000).build();
httpGet.setConfig(requestConfig);
CloseableHttpResponse response = httpclient.execute(httpGet);
System.out.println("得到的结果:" + response.getStatusLine());//得到请求结果
HttpEntity entity = response.getEntity();//得到请求回来的数据
  • setConnectTimeout:设置连接超时时间,单位毫秒。ConnectTimeoutException
  • setConnectionRequestTimeout:设置从connect Manager获取Connection 超时时间,单位毫秒。这个属性是新加的属性,因为目前版本是可以共享连接池的。ConnectionPoolTimeout
  • setSocketTimeout:请求获取数据的超时时间,单位毫秒。 如果访问一个接口,多少时间内无法返回数据,就直接放弃此次调用。SocketTimeoutException
  • 上面3个时间4.5版本默认是-1,就是不限,如果不设置就会一直等待

java.lang.IllegalStateException: Connection pool shut down的更多相关文章

  1. Android开发中使用数据库时出现java.lang.IllegalStateException: Cannot perform this operation because the connection pool has been closed.

    最近在开发一个 App 的时候用到了数据库,可是在使用数据库的时候就出现了一些问题,在我查询表中的一些信息时出现了一下问题: Caused by: java.lang.IllegalStateExce ...

  2. java.lang.IllegalStateException: Invalid use of BasicClientConnManager: connection still allocated.

    java.lang.IllegalStateException: Invalid use of BasicClientConnManager: connection still allocated.M ...

  3. [spring cloud] [error] java.lang.IllegalStateException: Only one connection receive subscriber allowed.

    前言 最近在开发api-gateway的时候遇到了一个问题,网上能够找到的解决方案也很少,之后由公司的大佬解决了这个问题.写下这篇文章记录一下解决方案.希望可以帮助到更多的人. 环境 java版本:8 ...

  4. java.lang.IllegalStateException

    java.lang.IllegalStateExceptionorg.apache.catalina.connector.ResponseFacade.sendRedirect(ResponseFac ...

  5. java.lang.IllegalStateException: Illegal access: this web application instance has been stopped already. Could not load [META-INF/services/com.alibaba.druid.filter.Filter].

    九月 11, 2019 2:56:36 下午 org.apache.catalina.loader.WebappClassLoaderBase checkStateForResourceLoading ...

  6. myeclipse 无法启动 java.lang.IllegalStateException: Unable to acquire application service. Ensure that the org.eclipse.core.runtime bundle is resolved and started (see config.ini).

    把myeclipse10 按照目录完整拷贝到了另外一台电脑, 另外的目录 原安装目录 D\:\soft\i\myeclipse10 新安装目录 E\:\soft\myeclipse10 双击启动失败, ...

  7. java.lang.IllegalStateException:Couldn't read row 0, col -1 from CursorWindow. Make sure the Cursor is initialized correctly before accessing data from it.

    java.lang.RuntimeException: Unable to start activity ComponentInfo{com.xxx...}: java.lang.IllegalSta ...

  8. java.lang.IllegalStateException: Not allowed to create transaction on shared EntityManager - use Spring transactions or EJB CMT instead

    java.lang.IllegalStateException: Not allowed to create transaction on sharedEntityManager - use Spri ...

  9. java.lang.IllegalStateException: getOutputStream() has already been called for this response

    ERROR [Engine] StandardWrapperValve[jsp]: Servlet.service() for servlet jsp threw exceptionjava.lang ...

随机推荐

  1. npm脚本传参问题

    npm脚本传参问题(比如设置env参数) windows环境下: "build": "set NODE_ENV=dev&& gulp", &qu ...

  2. 并发研究之CPU缓存一致性协议(MESI)

    CPU缓存一致性协议MESI CPU高速缓存(Cache Memory) CPU为何要有高速缓存 CPU在摩尔定律的指导下以每18个月翻一番的速度在发展,然而内存和硬盘的发展速度远远不及CPU.这就造 ...

  3. CSS之垂直对齐

    vertical-align: baseline 默认.元素放置在父元素的基线上. sub 垂直对齐文本的下标. super 垂直对齐文本的上标 top 把元素的顶端与行中最高元素的顶端对齐 text ...

  4. 金蝶k/3 现金流量表编制口诀

    现金流量表编制口诀 现金流量表是会计考试中十分令人头疼的内容,丢三落四是现金流量表编制中最容易出现的错误.下面的口诀基本上概括了现金流量表的全部编制过程.口诀的具体内容如何理解,我们在口诀后边详细阐述 ...

  5. (四)Knockout 表单

    click <div> You've clicked <span data-bind="text: numberOfClicks"></span> ...

  6. 不装插件,查看.rp文件

    AxShare国内平台地址:http://share.axure.org临时急用可以使用公用帐户.用户名:axure@webppd.com,密码:webppd123 上传.rp文件,点击 url 地址 ...

  7. Burnside引理与Polya定理 学习笔记

    原文链接www.cnblogs.com/zhouzhendong/p/Burnside-Polya.html 问题模型 有一个长度为 $n$ 的序列,序列中的每一个元素有 $m$ 种取值. 如果两个序 ...

  8. CodeForces 553E Kyoya and Train 动态规划 多项式 FFT 分治

    原文链接http://www.cnblogs.com/zhouzhendong/p/8847145.html 题目传送门 - CodeForces 553E 题意 一个有$n$个节点$m$条边的有向图 ...

  9. vue-cli 构建的项目中 如何使用less

    vue-cli 构建的项目默认是不支持 less 的,需要自己添加. 首选,安装 less 和 less-loader ,在项目目录下运行如下命令 npm install less less-load ...

  10. 2017-2018 ACM-ICPC, NEERC, Northern Subregional Contest

    A. Auxiliary Project 完全背包. #include<stdio.h> #include<iostream> #include<string.h> ...