Jaka jest różnica między CloseableHttpClient i HttpClient w Apache HttpClient API?

83

Studiuję aplikację stworzoną przez naszą firmę. Używa biblioteki Apache HttpClient. W kodzie źródłowym wykorzystuje HttpClientklasę do tworzenia instancji do łączenia się z serwerem.

Chcę dowiedzieć się więcej o Apache HttpClient i przejrzałem ten zestaw przykładów . Wszystkie przykłady używają CloseableHttpClientzamiast HttpClient. Myślę więc, że CloseableHttpClientjest to rozszerzona wersja HttpClient. Jeśli tak jest, mam dwa pytania:

  • Jaka jest różnica między tymi dwoma?
  • Która klasa jest zalecana do mojego nowego rozwoju?
Nayana Adassuriya
źródło
7
Dokumentacja wydaje mi się całkiem jasna: „Podstawowa implementacja HttpClient, która również implementuje Closeable” - HttpClient to interfejs; CloseableHttpClient jest klasą abstrakcyjną, ale ponieważ implementuje AutoCloseable, można jej użyć w instrukcji try-with-resources.
Jon Skeet,
3
@JonSkeet To jasne, ale jak ważne jest zamykanie HttpClientinstancji? Jeśli jest to ważne, dlaczego close()metoda nie jest częścią podstawowego interfejsu?
Jules
3
@Jules: Obawiam się, że nie wiem wystarczająco dużo o HttpClient, aby odpowiedzieć, że :(
Jon Skeet
close nie musi być częścią podstawowego interfejsu, ponieważ podstawowe połączenie jest automatycznie zwalniane z powrotem do menedżera połączeń
Jeril Kuruvila

Odpowiedzi:

100
  • Głównym punktem wejścia interfejsu API HttpClient jest interfejs HttpClient.
  • Najważniejszą funkcją HttpClient jest wykonywanie metod HTTP.
  • Wykonanie metody HTTP obejmuje jedną lub kilka wymian żądań HTTP / odpowiedzi HTTP, zwykle obsługiwanych wewnętrznie przez HttpClient.

  • CloseableHttpClient to klasa abstrakcyjna, która jest podstawową implementacją HttpClient, która również implementuje java.io.Closeable.
  • Oto przykład procesu realizacji żądania w jego najprostszej formie:

    CloseableHttpClient httpclient = HttpClients.createDefault ();
    HttpGet httpget = nowy HttpGet ("http: // localhost /");
    Odpowiedź CloseableHttpResponse = httpclient.execute (httpget);
    próbować {
        //Zrób coś
    } Wreszcie {
        response.close ();
    }

  • Cofnięcie alokacji zasobów HttpClient: gdy wystąpienie CloseableHttpClient nie jest już potrzebne i ma wyjść poza zakres, skojarzony z nim menedżer połączeń musi zostać zamknięty, wywołując metodę CloseableHttpClient # close ().

    CloseableHttpClient httpclient = HttpClients.createDefault ();
    próbować {
        //Zrób coś
    } Wreszcie {
        httpclient.close ();
    }

zobacz dokumentację, aby poznać podstawy.


@Scadge Od wersji Java 7 użycie instrukcji try-with-resources zapewnia, że ​​każdy zasób jest zamknięty na końcu instrukcji. Może być używany zarówno dla klienta, jak i dla każdej odpowiedzi

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
}
Sagar Pudi
źródło
57
Ta odpowiedź rodzi pytanie. Co powoduje wywołanie funkcji close () na HttpClient, co w przeciwnym razie by się nie wydarzyło? Czy przeciekasz połączenia, jeśli nie wywołujesz funkcji close () w odpowiednim czasie / miejscu? Czy wywołanie funkcji close () przedwcześnie wpływa na wydajność, powodując ponowne połączenie, gdy naprawdę nie było takiej potrzeby?
gilbertpilz
4
Przejrzałem kod w httpclient, szukając odpowiedzi na to pytanie. Odpowiedź jest taka, że ​​metoda close służy do zamykania stanu wewnętrznego. Niektóre implementacje HTTPClient (w bibliotece httpclient lib) można skonfigurować tak, aby korzystały z trwałych zasobów, takich jak PooledHttpClientConnectionManager, dla połączeń w puli i bez takiej metody nie można by w razie potrzeby wyczyścić tych zasobów.
Deadron
@SugarPudi w powyższym przykładzie, czy musimy httpgetrównież zamknąć
Kasun Siyambalapitiya
Jak możemy tutaj wywołać metody z klasy abstrakcyjnej (CloseableHttpClient)? Czy nie powinniśmy najpierw utworzyć konkretnej podklasy?
illcar
@illcar Proszę przejść przez tę odpowiedź, aby zrozumieć koncepcję stackoverflow.com/a/4321402/2830834
Sagar Pudi
26

Miałem to samo pytanie. Inne odpowiedzi nie wydają się odpowiadać, dlaczego metoda close () jest naprawdę konieczna? Wydawało się również, że Op ma problem ze znalezieniem preferowanego sposobu pracy z HttpClient i in.


Według 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.

Ponadto relacje wyglądają następująco:

HttpClient (berło)

wprowadzony przez:

CloseableHttpClient - ThreadSafe.

DefaultHttpClient- ThreadSafe, ALE przestarzałe , użyj HttpClientBuilderzamiast tego.

HttpClientBuilder- NIE ThreadSafe, ALE tworzy ThreadSafe CloseableHttpClient.

  • Służy do tworzenia CUSTOM CloseableHttpClient.

HttpClients- NIE ThreadSafe, ALE tworzy ThreadSafe CloseableHttpClient.

  • Służy do tworzenia DEFAULT lub MINIMAL CloseableHttpClient.

Preferowany sposób według Apache:

CloseableHttpClient httpclient = HttpClients.createDefault();

Przykład dają robi httpclient.close()w finallyklauzuli, a także posługuje się ResponseHandlerrównież.


Alternatywnie sposób, w jaki robi to mkyong, jest również nieco interesujący:

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

Nie pokazuje client.close()połączenia, ale myślę, że jest to konieczne, ponieważ clientnadal jest przykładem CloseableHttpClient.

euphoria99
źródło
15

Inne odpowiedzi wydają się nie wyjaśniać, dlaczego close()jest to naprawdę konieczne? * 2

Wątpliwości dotyczące odpowiedzi „Cofnięcie alokacji zasobów HttpClient”.

Jest wspomniany w starym dokumencie httpcomponents 3.x , który jest dawno temu i różni się znacznie od HC 4.x. Poza tym wyjaśnienie jest tak krótkie, że nie mówi, czym jest ten podstawowy zasób.

Zrobiłem trochę badań nad kodem źródłowym wydania 4.5.2, stwierdziłem, że implementacje w CloseableHttpClient:close()zasadzie tylko zamyka jego menedżera połączeń.

(FYI) Dlatego, gdy używasz współdzielonego PoolingClientConnectionManageri wywołującego klienta close(), java.lang.IllegalStateException: Connection pool shut downwystąpi wyjątek . Aby tego uniknąć, setConnectionManagerShareddziała.

Wolę nie robić CloseableHttpClient:close()po każdej prośbie

Kiedyś tworzyłem nową instancję klienta http podczas wykonywania żądania i ostatecznie ją zamykałem. W takim przypadku lepiej nie dzwonić close(). Ponieważ, jeśli menedżer połączeń nie ma flagi „udostępniony”, zostanie zamknięty, co jest zbyt kosztowne dla pojedynczego żądania.

W rzeczywistości znalazłem również w bibliotece clj-http , opakowanie Clojure nad Apache HC 4.5, w ogóle nie wywołuje close(). Zobacz func requestw pliku core.clj

eval
źródło
1
Czy możesz wyjaśnić, dlaczego jest to lepsze niż użycie setConnectionManagerShared i wywołanie funkcji close () po każdym żądaniu?
zyfo2
9

W kolejnej większej wersji HttpClientinterfejs biblioteki ma zostać rozszerzony Closeable. Do tego czasu zalecane jest używanie, CloseableHttpClientjeśli nie jest wymagana zgodność z wcześniejszymi wersjami 4.x (4.0, 4.1 i 4.2).

ok2c
źródło
8

HttpClientto nie klasa, to interfejs. Nie możesz go wykorzystać do rozwoju w sposób, jaki masz na myśli.

To, czego chcesz, to klasa, która implementuje HttpClientinterfejs, i to jest CloseableHttpClient.

M. Sfakianos
źródło
2

CloseableHttpClientjest podstawową klasą biblioteki httpclient, której używają wszystkie implementacje. Inne podklasy są w większości przestarzałe.

HttpClientJest interfejsem dla tej klasy i innych klas.

Następnie należy użyć CloseableHttpClientw swoim kodzie i utworzyć go przy użyciu HttpClientBuilder. Jeśli chcesz opakować klienta w celu dodania określonego zachowania, powinieneś użyć przechwytywaczy żądań i odpowiedzi zamiast zawijania za pomocą HttpClient.

Ta odpowiedź została udzielona w kontekście httpclient-4.3.

polve
źródło
0

Jon Skeet powiedział:

Dokumentacja wydaje mi się całkiem jasna: „Podstawowa implementacja HttpClient, która również implementuje Closeable” - HttpClient to interfejs; CloseableHttpClient jest klasą abstrakcyjną, ale ponieważ implementuje AutoCloseable, można jej użyć w instrukcji try-with-resources.

Ale potem Jules zapytał:

@JonSkeet To jasne, ale jak ważne jest zamykanie instancji HttpClient? Jeśli to ważne, dlaczego metoda close () nie jest częścią podstawowego interfejsu?

Odpowiedź dla Julesa

close nie musi być częścią podstawowego interfejsu, ponieważ podstawowe połączenie jest automatycznie zwalniane z powrotem do menedżera połączeń po każdym wykonaniu

Aby uwzględnić instrukcję try-with-resources. Wdrożenie Zamknięcie jest obowiązkowe. Dlatego uwzględniono go w CloseableHttpClient .

Uwaga:

close metoda w AbstractHttpClient, która rozszerza CloseableHttpClient, jest przestarzała, nie mogłem znaleźć kodu źródłowego do tego.

Jeril Kuruvila
źródło
To nadal nie wydaje się odpowiadać „jak ważne jest zamykanie wystąpień HttpClient?”
Vivek Chavda