CloseableHttpResponse用完需要手动关闭吗

标签: java

不用。

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

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

版权声明:本文为cg_Amaz1ng原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/cg_Amaz1ng/article/details/104879658

智能推荐

异常数据处理——箱型图分析原理及Python例程

箱型图分析原理及Python例程  一、箱型图分析原理 箱型图可以通过程序设置一个识别异常值的标准,即大于或小于箱型图设定的上下界的数值则识别为异常值,箱型图如下图所示: 首先我们定义下上四分位和下四分位: 上四分位我们设为 U,表示的是所有样本中只有1/4的数值大于U ,即从大到小排序时U处于25%处; 同理,下四分位我们设为 L,表示的是所有样本中只有1/4的数值...

2019.3.11

2019.3.11...

面试题49. 把字符串转换为整数

面试题49. 把字符串转换为整数 题目描述 将一个字符串转换成一个整数,要求不能使用字符串转换整数的库函数。 数值为0或者字符串不是一个合法的数值则返回0 输入描述: 输入一个字符串,包括数字字母符号,可以为空 输出描述: 如果是合法的数值表达则返回该数字,否则返回0 示例1 输入 +2147483647 1a33 输出 2147483647 0 思路: 对于输入的字符串,从后向前遍历,判断每一位...

Mysql入门——创建一个数据库

题目:创建一个教务管理数据库,名称为 JWGL 在 JWGL 数据库中创建学生表 Student、课程表 Course、学生选课表 SC,它们的表结构如下所示: 学生表Student 列名 数据类型 长度 允许空值 默认值 说明 Sno char 8 × 主键 Sname varchar 10 × Sex char 2 × 男 只能“男”...

猜你喜欢

从上到下打印二叉树

题目 从上到下打印出二叉树的每个节点,每层的节点按照从左到右的顺序打印。 例子:   打印顺序:8,6,10,5,7,9,11 二叉树节点定义: 思路: 本题实际上是层序遍历二叉树,根据题目特点,选用队列来存储相应节点,每次取出队列头部元素,如果该元素有子节点,将子节点放入队列中,如此循环。 代码 测试以及结果   总结 本题区别与二叉树的前中后序遍历,它们都是通过栈数据结构来...

Java GUI编程(13)---GridBagLayout网格袋布局

GridBagLayout(),网格袋布局,维持一个动态的矩形单元的网格,矩形单元格被称为显示区域。 组件可占用一个或多个的矩形单元格,组件不要求相同尺寸。 组件由GridBagLayou管理,关联一个约束GridBagConstraints类。 约束组件属性,比如:位置,大小,外部填充,内部填充等。 GridBagConstraints Class 约束属性与值 int gridx,gridy;...

h.264 aac librtmp推流应用

librtmp + h.264(MediaCodec) + aac(MediaCodec) + ams5 demo:https://github.com/wangzuxing/myrtmplive pc需安装ams5, 作为流服务器,android端通过pc端ip + ams5 rtmp端口跟流服务器建立连接(NetConnection) h.264: 摄像头预览数据 MediaCodec 编码(...

Conditional Generative Adversarial Nets

Introduction 对抗生成网络通过迭代的方式训练生成模型,可以避免棘手的概率近似。它不需要用到马尔可夫链这么复杂的东西,仅仅需要通过反向传播学习梯度。Goodfellow2014年在《Generative adversarial nets》指出它可以产生最先进的对数似然估计和现实样本。 这篇文章提出一种带条件的生成对抗网络(判别器和生成器都带条件)。在不带条件的对抗网络中,数据生成的模式不...

LeetCode快慢指针遍历和Hash高频题(二)

我是方圆 “无它,唯手熟尔” 题号 141. 环形链表 202. 快乐数 876. 链表的中间节点 1. 两数之和(Hash相关) 141. 环形链表 给定一个链表,判断链表中是否有环。 为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环 示例: 输入:head = [3,2,0,-...