为什么作者使用EntityUtils.consume(httpEntity);?

时间:2013-04-12 10:31:09

标签: java apache-httpclient-4.x

我遇到过EntityUtils.consume(httpEntity);,我不确定它到底是做什么的。

例如:

try {

    //... some code

    HttpEntity httpEntity = httpResponse.getEntity();
    BufferedReader br = new BufferedReader(new InputStreamReader(http.Entity.getContent()));
    String line;
    while ((line = br.readLine())!= null) {
        System.out.println(line);
    }
    EntityUtils.consume(httpEntity);
} catch (Exception e) {
    //code
} finally { 
    httpClient.getConnectionManager().shutdown();
}

为什么当EntityUtils.consume(httpEntity);块关闭连接并且垃圾收集器将处理finally时,作者放入httpEntity

1 个答案:

答案 0 :(得分:41)

它真的归结为成为“好公民”(并且真正了解HTTPClient接口的合同)。 EntityUtils.consume将执行的操作是释放httpEntity所拥有的所有资源,这实际上意味着释放任何基础Stream并将Connection对象返回其池(如果您的连接管理器是多线程的)或者释放连接管理器,以便它可以处理下一个请求。

如果您不使用entity,那么实际发生的事情取决于“关闭连接管理器”在finally子句中的含义。它会关闭尚未发送回池的待处理流/连接吗?我不确定它会在合同上做到这一点(尽管我认为它是实现性的)。如果没有,那么您可能会泄漏系统资源(套接字等)。 发生的事情也可能取决于Entity对象的可能的最终化方法,该方法可能(如果它完全被执行)释放其资源,同样,不确定它是否在实体的合同中。

让我们假设ConnectionManager在关闭时正常关闭所有待处理资源。你还需要消费实体吗?我说是的,因为从现在起一个月后,有人会修改你的代码并在同一个try / finally块中进行第二次HTTP调用,并且可能无法这样做,因为你没有以你应该拥有的方式释放资源(例如,如果你的客户端在一个连接池上,没有释放第一个连接会使第二次调用失败)。

所以我的观点是:实体是资源,资源应该在不需要时释放。指望别人在以后为你释放它们可能会在将来伤害你。原作者可能已经考虑过这些思路。

作为旁注,请注意您编写的实现实际上会将读取器消耗到底层流的末尾,因此消耗调用实际上什么都不做,但在我看来,这是一个实现细节(从我的头脑中,一旦完全读取了响应流,连接对象就会自动释放/发送回http客户端中的池。 另请注意,如果您使用API​​提供的ResponseHandler机制,所有这些Consume逻辑也会从您身上抽象出来。 最后,API不保证response.getEntity永远不会返回null,因此您应该检查以避免NullPointerException