CloseableHttpResponse用完需要手动关闭吗

不用。

前提是调用了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这个输入流。

老眼昏花,写的比较乱。太难了。。。。。

  • 15
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值