web-dev-qa-db-ja.com

なぜ著者はEntityUtils.consume(httpEntity);を使用したのですか?

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();
}
_

finallyブロックが接続を閉じ、ガベージコレクターがhttpEntityを処理するときに、著者がEntityUtils.consume(httpEntity);を挿入したのはなぜですか?

33
chris loughnane

要するに、「善良な市民」であるということになります(そして、HTTPClientインターフェースの契約を本当に知っている)。何 EntityUtils.consumehttpEntityによって保持されているすべてのリソースを解放します。これは、基本となるStreamを解放し、Connectionオブジェクトをそのプールに戻すことを意味します(接続マネージャーがマルチスレッドの場合)次のリクエストを処理できるようにするためのマネージャー。

entityを消費しない場合、実際に何が起こるかは、finally節の「接続マネージャーのシャットダウン」の意味に依存します。プールに送り返されていない保留中のストリーム/接続を閉じますか?それが契約上それを行うかどうかはわかりません(実装に関してはそうだと思いますが)。そうでない場合は、システムリソース(ソケットなど)がリークしている可能性があります。何が起こるかは、エンティティオブジェクトの可能な最終化メソッドに依存することもあります。このメソッドは、実行された場合、リソースを解放する可能性があります。

ConnectionManagerがシャットダウン時に保留中のすべてのリソースを実際に正常に閉じると仮定しましょう。まだエンティティを消費する必要がありますか? 1か月後に誰かがコードを変更し、同じtry/finallyブロックで2回目のHTTP呼び出しを行うため、必要な方法でリソースを解放していないため、そうできない場合があるためですクライアントは単一の接続プール上にあり、最初の接続を解放しないと2番目の呼び出しは失敗します)。

だから私のポイントは次のとおりです。エンティティはリソースであり、リソースは不要になったら解放する必要があります。後で他の人に頼って解放してもらうと、将来あなたを傷つける可能性があります。原作者はそれらの線に沿って考えたかもしれません。

サイドノートとして、あなたが書いた実装は、実際に基礎となるストリームの終わりまでリーダーを消費することに注意してください。したがって、消費呼び出しは実際には何もしませんが、私の意見では、これは実装の詳細です頭の中で、応答ストリームが完全に読み取られると、接続オブジェクトは自動的に解放され、httpクライアントのプールに送り返されます)。 APIが提供するResponseHandlerメカニズムを使用すると、このConsumeロジックもすべて抽象化されることに注意してください。最後に、APIはresponse.getEntityは決してnullを返さないので、NullPointerExceptionを避けるためにそれをチェックする必要があります。

41
GPI