У чому різниця між CloseableHttpClient та HttpClient в Apache HttpClient API?


83

Я вивчаю додаток, розроблений нашою компанією. Він використовує бібліотеку Apache HttpClient. У вихідному коді він використовує HttpClientклас для створення екземплярів для підключення до сервера.

Я хочу дізнатися про Apache HttpClient, і я пройшов цей приклад . Усі приклади використовують CloseableHttpClientзамість HttpClient. Тому я думаю CloseableHttpClient, що це розширена версія HttpClient. Якщо це так, у мене є два запитання:

  • Яка різниця між цими двома?
  • Який клас рекомендується використовувати для моєї нової розробки?

7
Мені здається досить зрозумілою документація: "Базова реалізація HttpClient, яка також реалізує Closeable" - HttpClient - це інтерфейс; CloseableHttpClient - це абстрактний клас, але оскільки він реалізує AutoCloseable, ви можете використовувати його в операторі try-with-resources.
Джон Скіт,

3
@JonSkeet Це зрозуміло, але наскільки важливо закривати HttpClientекземпляри? Якщо це важливо, чому close()метод не є частиною базового інтерфейсу?
Жуль

3
@Jules: Боюсь, я недостатньо знаю про HttpClient, щоб відповісти на це :(
Джон Скіт,

close не повинен бути частиною базового інтерфейсу, оскільки базове з'єднання автоматично вивільняється назад до менеджера з'єднань
Jeril Kuruvila

Відповіді:


98
  • Основною точкою входу API HttpClient є інтерфейс HttpClient.
  • Найважливішою функцією HttpClient є виконання методів HTTP.
  • Виконання методу HTTP передбачає один або кілька обмінів запитів HTTP / відповідей HTTP, які зазвичай обробляються внутрішньо HttpClient.

  • CloseableHttpClient - це абстрактний клас, який є базовою реалізацією HttpClient, який також реалізує java.io.Closeable.
  • Ось приклад процесу виконання запиту в найпростішій формі:

    CloseableHttpClient httpclient = HttpClients.createDefault ();
    HttpGet httpget = новий HttpGet ("http: // localhost /");
    CloseableHttpResponse відповідь = httpclient.execute (httpget);
    спробуй {
        //робити щось
    } нарешті {
        response.close ();
    }

  • Вивільнення ресурсу HttpClient: Коли екземпляр CloseableHttpClient більше не потрібен і збирається вийти за межі обсягу, пов'язаний з ним менеджер з'єднань повинен бути вимкнений, викликаючи метод CloseableHttpClient # close ().

    CloseableHttpClient httpclient = HttpClients.createDefault ();
    спробуй {
        //робити щось
    } нарешті {
        httpclient.close ();
    }

дивіться Довідник, щоб вивчити основи.


@Scadge Починаючи з Java 7, використання оператора try-with-resources забезпечує закриття кожного ресурсу в кінці оператора. Його можна використовувати як для клієнта, так і для кожної відповіді

try(CloseableHttpClient httpclient = HttpClients.createDefault()){

    // e.g. do this many times
    try (CloseableHttpResponse response = httpclient.execute(httpget)) {
    //do something
    }

    //do something else with httpclient here
}

57
Ця відповідь напрошує запитання. Що викликає виклик close () на HttpClient, який інакше не відбувся б? Чи витікають зв’язки, якщо ви не телефонуєте в close () у відповідний час / місця? Чи дзвінок close () передчасно впливає на вашу продуктивність, змушуючи вас повторно підключатися, коли вам справді не потрібно було?
gilbertpilz

4
Я переглянув код у httpclient, щоб знайти відповідь на це питання. Відповідь полягає в тому, що метод закриття використовується для закриття внутрішнього стану. Деякі реалізації HTTPClient (у бібліотеці httpclient) можна налаштувати на використання постійних ресурсів, таких як PooledHttpClientConnectionManager, для об'єднаних з'єднань, і без такого методу ви не зможете очистити ці ресурси, якщо це потрібно.
Дедрон

@SugarPudi у наведеному вище прикладі, чи потрібно нам httpgetтакож закривати
Касун Сіямбалапітія

Як ми можемо тут викликати методи абстрактного класу (CloseableHttpClient)? Чи не слід спочатку створити конкретний підклас?
illcar

@illcar Будь ласка, надішліть цю відповідь, щоб зрозуміти концепцію stackoverflow.com/a/4321402/2830834
Сагар Пуді

26

Було те саме питання. Інші відповіді, здається, не стосуються того, чому насправді потрібно close ()? Крім того, Оп, здається, намагається з'ясувати, який найкращий спосіб працювати з HttpClient та ін.


За словами Апача :

// The underlying HTTP connection is still held by the response object
// to allow the response content to be streamed directly from the network socket.
// In order to ensure correct deallocation of system resources
// the user MUST call CloseableHttpResponse#close() from a finally clause.

Крім того, відносини йдуть наступним чином:

HttpClient (інтерфейс)

реалізує:

CloseableHttpClient - ThreadSafe.

DefaultHttpClient- ThreadSafe АЛЕ застарілий , використовуйте HttpClientBuilderзамість цього.

HttpClientBuilder- НЕ ThreadSafe, АЛЕ створює ThreadSafe CloseableHttpClient.

  • Використовуйте для створення CUSTOM CloseableHttpClient.

HttpClients- НЕ ThreadSafe, АЛЕ створює ThreadSafe CloseableHttpClient.

  • Використовуйте для створення DEFAULT або MINIMAL CloseableHttpClient.

Кращий спосіб згідно Apache:

CloseableHttpClient httpclient = HttpClients.createDefault();

Приклад, який вони наводять, міститься httpclient.close()в finallyреченні, а також використовує ResponseHandlerтакож.


Як альтернатива, спосіб роботи mkyong також є трохи цікавим:

HttpClient client = HttpClientBuilder.create().build();

Він не показує client.close()дзвінок, але я вважаю, що це необхідно, оскільки clientвсе ще є екземпляром CloseableHttpClient.


15

Інші відповіді, здається, не стосуються того, чому close()це насправді потрібно? * 2

Сумнів у відповіді "Виділення ресурсів HttpClient".

Це згадується у старому документі httpxponents 3.x , який давно повернувся і має велику різницю від 4.x HC. До того ж пояснення настільки коротке, що не сказано, що це за основний ресурс.

Я провів деякі дослідження щодо вихідного коду випуску 4.5.2, виявив, що реалізація в CloseableHttpClient:close()основному закриває лише менеджер підключень.

(FYI) Ось чому при використанні спільного PoolingClientConnectionManagerклієнта та клієнта виклику відбудеться close()виняток java.lang.IllegalStateException: Connection pool shut down. Щоб уникнути, setConnectionManagerSharedпрацює.

Я вважаю за краще не робити CloseableHttpClient:close()після кожного окремого запиту

Раніше я створював новий екземпляр клієнта http під час виконання запиту і нарешті закрив його. У цьому випадку краще не дзвонити close(). Оскільки, якщо менеджер з’єднань не має прапорця "спільного доступу", його буде вимкнено, що занадто дорого для одного запиту.

Насправді я також знайшов у бібліотеці clj-http , обгортку Clojure над Apache HC 4.5 взагалі не викликає close(). Див. Func requestу файлі core.clj


1
Не могли б ви пояснити, чому це краще, ніж використовувати setConnectionManagerShared і викликати close () після кожного запиту?
zyfo2

9

У наступній великій версії HttpClientінтерфейс бібліотеки буде розширений Closeable. До цього часу рекомендується використовувати, CloseableHttpClientякщо сумісність із попередніми версіями 4.x (4.0, 4.1 та 4.2) не потрібна.


8

HttpClientце не клас, це інтерфейс. Ви не можете використовувати його для розвитку так, як ви маєте на увазі.

Що вам потрібно, це клас, який реалізує HttpClientінтерфейс, і це є CloseableHttpClient.


2

CloseableHttpClientє базовим класом бібліотеки httpclient, яким користуються всі реалізації. Інші підкласи здебільшого застаріли.

Це HttpClientінтерфейс для цього класу та інших класів.

Потім вам слід використовувати CloseableHttpClientкод у своєму коді та створити його за допомогою HttpClientBuilder. Якщо вам потрібно обернути клієнта, щоб додати конкретну поведінку, ви повинні використовувати перехоплювачі запитів та відповідей замість обгортання HttpClient.

Ця відповідь була дана в контексті httpclient-4.3.


0

Джон Скіт сказав:

Мені здається досить зрозумілою документація: "Базова реалізація HttpClient, яка також реалізує Closeable" - HttpClient - це інтерфейс; CloseableHttpClient - це абстрактний клас, але оскільки він реалізує AutoCloseable, ви можете використовувати його в операторі try-with-resources.

Але тоді Жуль запитав:

@JonSkeet Це зрозуміло, але наскільки важливо закривати екземпляри HttpClient? Якщо це важливо, чому метод close () не є частиною базового інтерфейсу?

Відповідь для Жуля

close не повинен бути частиною базового інтерфейсу, оскільки базове з'єднання автоматично вивільняється назад до менеджера з'єднань після кожного виконання

Для розміщення оператора try-with-resources. Обов’язковим є впровадження Closeable. Звідси включив його до CloseableHttpClient .

Примітка:

Метод close в AbstractHttpClient, який розширюється CloseableHttpClient, застарілий, мені не вдалося знайти вихідний код для цього.


Здається, це все ще не відповідає "наскільки важливо закривати екземпляри HttpClient?"
Вівек Чавда,
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.