В чем разница между CloseableHttpClient и HttpClient в Apache HttpClient API?


84

Я изучаю приложение, разработанное нашей компанией. Он использует библиотеку 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 не обязательно должен быть частью базового интерфейса, так как базовое соединение автоматически
передается обратно

Ответы:


100
  • Основная точка входа в HttpClient API - это интерфейс HttpClient.
  • Самая важная функция HttpClient - выполнение HTTP-методов.
  • Выполнение метода HTTP включает в себя один или несколько обменов HTTP-запросом / HTTP-ответом, обычно обрабатываемым внутри HttpClient.

  • CloseableHttpClient - это абстрактный класс, который является базовой реализацией HttpClient, который также реализует java.io.Closeable.
  • Вот пример процесса выполнения запроса в простейшем виде:

    CloseableHttpClient httpclient = HttpClients.createDefault ();
    HttpGet httpget = new HttpGet ("http: // localhost /");
    CloseableHttpResponse response = 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
}

58
Этот ответ вроде как напрашивается вопрос. Что вызывает вызов close () для HttpClient, чего в противном случае не произошло бы? У вас утечка соединений, если вы не вызываете close () в подходящее время / место? Вызов close () преждевременно влияет на вашу производительность, заставляя вас повторно подключаться, когда в этом действительно не было необходимости?
gilbertpilz

4
Я просмотрел код в httpclient, чтобы найти ответ на этот вопрос. Ответ заключается в том, что метод close используется для закрытия внутреннего состояния. Некоторые реализации HTTPClient (в httpclient lib) можно настроить для использования постоянных ресурсов, таких как PooledHttpClientConnectionManager, для соединений в пуле, и без такого метода вы не смогли бы очистить эти ресурсы при необходимости.
Deadron

@SugarPudi в приведенном выше примере, мы должны закрыть httpgetтакже
Kasun Siyambalapitiya

Как мы можем здесь вызывать методы абстрактного класса (CloseableHttpClient)? Не следует ли нам сначала создать конкретный подкласс?
illcar

@illcar Пожалуйста, прочтите этот ответ, чтобы понять концепцию stackoverflow.com/a/4321402/2830834
Сагар Пуди

27

Был такой же вопрос. Другие ответы, похоже, не объясняют, почему close () действительно необходим? Кроме того, Op, похоже, изо всех сил пытался выяснить предпочтительный способ работы с HttpClient и др.


Согласно Apache :

// 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.

  • Используйте для создания ПО УМОЛЧАНИЮ или МИНИМАЛЬНО CloseableHttpClient.

Предпочтительный способ согласно Apache:

CloseableHttpClient httpclient = HttpClients.createDefault();

Приведенный ими пример подходит и httpclient.close()для данного finallyпредложения, и также используется ResponseHandler.


В качестве альтернативы, способ, которым это делает mkyong, тоже немного интересен:

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

Он не показывает client.close()вызов, но я думаю, что это необходимо, так clientкак все еще является экземпляром CloseableHttpClient.


15

Другие ответы, похоже, не объясняют, почему close()это действительно необходимо? * 2

Сомневаюсь в ответе "Освобождение ресурса HttpClient".

Он упоминается в старом документе httpcomponents 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(). См. Funcrequest в файле 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 не обязательно должен быть частью базового интерфейса, поскольку базовое соединение передается обратно диспетчеру соединений автоматически после каждого выполнения

Чтобы приспособиться к заявлению "попробуйте с ресурсами". Обязательно реализовать Closeable. Следовательно, включил его в CloseableHttpClient .

Заметка:

Метод close в AbstractHttpClient, который расширяет CloseableHttpClient, устарел, мне не удалось найти для него исходный код.


Кажется, это все еще не отвечает на вопрос «насколько важно закрывать экземпляры HttpClient?»
Вивек Чавда,
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.