前提是调用了EntityUtils去读取过了。
当我们使用调用CloseableHttpClient的时候,调用CloseableHttpClient.execute(httpPost)方法会返回CloseableHttpResponse对象,CloseableHttpResponse的唯一实现类是HttpResponseProxy,我们来研究下不手动close,这个对象能否被正常回收,是否有资源被占用等bad situations
分析下HttpResponseProxy源码,发现这个类只有两个成员变量,分别是HttpResponse和ConnectionHolder:只要这俩被回收,就是jvm安全的。
HttpResponse在这里是BasicHttpResponse,这个对象里有一个HttpEntity的成员变量,HttpEntity里有一个输入流
只要这个流被回收了就是安全的。
然后再来看看ConnectionHolder里有什么
额,manager和managedConn这是什么?先不管,看下方法栈
只要manager和managedConn被回收了就是安全的。
好,我们回去看HttpResponseProxy,注意看HttpResponseProxy的构造函数,response这个对象被增强了,response.getEntity得到的对象将变ResponseEntityProxy,注意这个类实现了EofSensorWatcher
// 构造函数
public HttpResponseProxy(final HttpResponse original, final ConnectionHolder connHolder) {
this.original = original;
this.connHolder = connHolder;
ResponseEntityProxy.enchance(original, connHolder);
}
// 增强代码
class ResponseEntityProxy extends HttpEntityWrapper implements EofSensorWatcher {
private final ConnectionHolder connHolder;
public static void enchance(final HttpResponse response, final ConnectionHolder connHolder) {
final HttpEntity entity = response.getEntity();
if (entity != null && entity.isStreaming() && connHolder != null) {
response.setEntity(new ResponseEntityProxy(entity, connHolder));
}
}
当我们调用EntityUtils.toString方法去消费entity对象,这个方法会调用entity的getContent方法去获取输入流。
而这个entity就是增强后的这个ResponseEntityProxy,这个对象的getContent方法返回了EofSensorInputStream。(第二个参数this表示把这个inputStream的EofSensorWatcher设置为ResponseEntityProxy对象)
@Override
public InputStream getContent() throws IOException {
return new EofSensorInputStream(this.wrappedEntity.getContent(), this);
}
EofSensorInputStream.java
@Override
public int read(final byte[] b, final int off, final int len) throws IOException {
int l = -1;
if (isReadAllowed()) {
try {
l = wrappedStream.read(b, off, len);
checkEOF(l);
} catch (final IOException ex) {
checkAbort();
throw ex;
}
}
return l;
}
protected void checkEOF(final int eof) throws IOException {
final InputStream toCheckStream = wrappedStream;
if ((toCheckStream != null) && (eof < 0)) {
try {
boolean scws = true; // should close wrapped stream?
if (eofWatcher != null) {
scws = eofWatcher.eofDetected(toCheckStream);
}
if (scws) {
toCheckStream.close();
}
} finally {
wrappedStream = null;
}
}
}
ResponseEntityProxy实现EofSensorWatcher接口,这个就是HttpResponse里的entity对象,releaseConnection用于清除这个代理对象的connHolder对象,也就是HttpResponseProxy的ConnectionHolder对象。
@Override
public boolean eofDetected(final InputStream wrapped) throws IOException {
try {
// there may be some cleanup required, such as
// reading trailers after the response body:
if (wrapped != null) {
wrapped.close();
}
releaseConnection();
} catch (final IOException ex) {
abortConnection();
throw ex;
} catch (final RuntimeException ex) {
abortConnection();
throw ex;
} finally {
cleanup();
}
return false;
}
httpcomponent4.5以上版本,默认使用 EofSensorInputStream 作为输入流,这个流对象在每次读取之后都会检查是否已经读取到末尾,如果读取完,则关闭ChunkedInputStream并释放连接 releaseConnection(),就算没有关闭,如果是通过apache的EntityUtils的toString方法获取HttpEntity对象里的内容,也会在return之前执行finally里的close方法
releaseConnection这个方法释放了最开始我们提到的ConnectionHolder,而close方法则关闭了HttpResponse里的流,因此最后是安全的,即使没有手动调用close方法,全部得益于EofSensorInputStream这个输入流。
老眼昏花,写的比较乱。太难了。。。。。