web-dev-qa-db-fra.com

Pourquoi l'auteur a-t-il utilisé EntityUtils.consume (httpEntity) ;?

J'ai rencontré EntityUtils.consume(httpEntity); et je ne sais pas vraiment ce que ça fait.

Par exemple:

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

Pourquoi l'auteur a-t-il mis EntityUtils.consume(httpEntity); alors que le bloc finally ferme la connexion et que le garbage collector s'occupe de httpEntity?

34
chris loughnane

Cela revient vraiment à être un "bon citoyen" (et à vraiment connaître les contrats des interfaces HTTPClient). Quelle EntityUtils.consume va faire est de libérer toutes les ressources détenues par le httpEntity, ce qui implique essentiellement de libérer tout Stream sous-jacent et de redonner l'objet Connection à son pool (dans le cas où votre gestionnaire de connexions est multithread) ou de libérer la connexion gestionnaire afin qu'il puisse traiter la prochaine demande.

Si vous ne consommez pas le entity, ce qui se passe dépend vraiment de ce que signifie "arrêter le gestionnaire de connexions" dans la clause finally. Va-t-il fermer les flux/connexions en attente qui n'ont pas été renvoyés au pool? Je ne suis pas sûr qu'il le fera contractuellement (bien que pour la mise en œuvre, je pense que oui). Si ce n'est pas le cas, vous risquez de perdre des ressources système (sockets, etc.). Ce qui se passe peut également dépendre d'une méthode de finalisation possible de l'objet Entity qui peut (si elle est exécutée) libérer ses ressources, encore une fois, pas sûr qu'il soit dans le contrat de l'entité de le faire.

Supposons une minute que ConnectionManager ferme en fait toutes les ressources en attente lors de son arrêt. Auriez-vous encore besoin de consommer l'entité? Je dis oui, car dans un mois, quelqu'un modifiera votre code et fera un deuxième appel HTTP dans le même bloc try/finally, et pourrait ne pas être en mesure de le faire parce que vous n'avez pas libéré les ressources comme vous l'auriez dû (par exemple si votre client est sur un seul pool de connexion, ne pas libérer la première connexion fera échouer un deuxième appel).

Mon point est donc le suivant: les entités sont des ressources et les ressources doivent être libérées lorsqu'elles ne sont pas nécessaires. Compter sur les autres pour les libérer pour vous à un moment ultérieur peut vous blesser à l'avenir. L'auteur original a peut-être pensé dans ce sens.

En remarque, notez que l'implémentation que vous avez écrite consommera en fait le lecteur jusqu'à la fin du flux sous-jacent, donc l'appel consume ne fera rien du tout, mais à mon avis, c'est un détail d'implémentation (hors de la haut de ma tête, une fois qu'un flux de réponse a été complètement lu, l'objet de connexion est automatiquement libéré/renvoyé au pool dans le client http). Notez également que toute cette logique de consommation est également éloignée de vous si vous utilisez le mécanisme ResponseHandler proposé par l'API. Enfin, l'API ne garantit pas que response.getEntity ne renverra jamais null, vous devez donc vérifier cela pour éviter NullPointerException.

42
GPI