org.apache.http.conn.ConnectionPoolTimeoutException: Timeout waiting for connection from pool
问题描述:无法从httpClient连接池获取有效连接对象
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.util.EntityUtils;
@Resouce
CloseableHttpClient httpClient;
/**
*调用远程连接的时候,即是从httpClient 池中获取一个链接对象
*当调用结束,应该关闭连接,不然会占用资源,导致最后无可用的连接对象
**/
CloseableHttpResponse response = this.httpClient.execute(HttpGet);
/**
*关闭连接对象(即归还连接资源),以下两个方法都为关闭连接资源
**/
EntityUtils.toString(response.getEntity(), "UTF-8");//返回响应体的数据并关闭资源
EntityUtils.consumeQuietly(response.getEntity());//只是关闭连接资源
源码解析:
EntityUtils.toString(response.getEntity(), "UTF-8");
//源码展示
private static String toString(HttpEntity entity, ContentType contentType) throws IOException {
InputStream instream = entity.getContent();
if (instream == null) {
return null;
} else {
try {
Args.check(entity.getContentLength() <= 2147483647L, "HTTP entity too large to be buffered in memory");
int capacity = (int)entity.getContentLength();
if (capacity < 0) {
capacity = 4096;
}
Charset charset = null;
if (contentType != null) {
charset = contentType.getCharset();
if (charset == null) {
ContentType defaultContentType = ContentType.getByMimeType(contentType.getMimeType());
charset = defaultContentType != null ? defaultContentType.getCharset() : null;
}
}
if (charset == null) {
charset = HTTP.DEF_CONTENT_CHARSET;
}
Reader reader = new InputStreamReader(instream, charset);
CharArrayBuffer buffer = new CharArrayBuffer(capacity);
char[] tmp = new char[1024];
int l;
while((l = reader.read(tmp)) != -1) {
buffer.append(tmp, 0, l);
}
String var9 = buffer.toString();
return var9;
} finally {
/**
*最终关闭读取response流,即关闭连接资源
**/
instream.close();
}
}
}
EntityUtils.consumeQuietly(response.getEntity());
/**
*源码解析
**/
public static void consume(HttpEntity entity) throws IOException {
if (entity != null) {
if (entity.isStreaming()) {
InputStream instream = entity.getContent();
if (instream != null) {
/**
*最终都是把读取response响应体的读取流关闭,及关闭连接资源
**/
instream.close();
}
}
}
}
结论:
@Resouce
CloseableHttpClient httpClient;
httpClient 对象即是一个http连接池,从连接池中获取连接对象,即是获取读取流对象
一旦调用完远程接口,必须把 连接关闭(即关闭读取流)
所以httpClient调用远程接口的方法里都少不了最终的操作—关闭连接:
EntityUtils.consumeQuietly(response.getEntity());
没有关闭导致的问题如下:
一旦调用远程接口出错,响应码是500,或者其他错误码,连接无法释放,便一直占用着这个链接资源,而且回收机制并不会回收connect对象,因为它是处于活跃状态的,一直占用,当httpClient连接池资源耗尽,再想从连接池中获取连接connect对象时便会报一开始的错误