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這個輸入流。

老眼昏花,寫的比較亂。太難了。。。。。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章