Sự khác biệt giữa ClosableHttpClient và HttpClient trong Apache HttpClient API là gì?


83

Tôi đang nghiên cứu một ứng dụng do công ty chúng tôi phát triển. Nó sử dụng thư viện Apache HttpClient. Trong mã nguồn, nó sử dụng HttpClientlớp để tạo các thể hiện để kết nối với máy chủ.

Tôi muốn tìm hiểu về Apache HttpClient và tôi đã thử qua bộ ví dụ này . Tất cả các ví dụ sử dụng CloseableHttpClientthay vì HttpClient. Vì vậy, tôi nghĩ CloseableHttpClientlà một phiên bản mở rộng của HttpClient. Nếu đây là trường hợp, tôi có hai câu hỏi:

  • sự khác biệt giữa hai cái đó là gì?
  • Lớp nào được khuyến nghị sử dụng cho sự phát triển mới của tôi?

7
Tài liệu có vẻ khá rõ ràng đối với tôi: "Triển khai cơ sở của HttpClient cũng triển khai Closable" - HttpClient là một giao diện; ClosableHttpClient là một lớp trừu tượng, nhưng vì nó triển khai AutoClosable nên bạn có thể sử dụng nó trong câu lệnh try-with-resources.
Jon Skeet

3
@JonSkeet Điều đó đã rõ ràng, nhưng điều quan trọng là đóng các HttpClientphiên bản? Nếu nó quan trọng, tại sao close()phương thức không phải là một phần của giao diện cơ bản?
Jules

3
@Jules: Tôi e rằng tôi không biết đủ về HttpClient để trả lời rằng :(
Jon Skeet

cần gần không là một phần của giao diện cơ bản kể từ khi cơ bản kết nối được phát hành trở lại cho người quản lý kết nối tự động
Jeril Kuruvila

Câu trả lời:


98
  • Điểm nhập chính của HttpClient API là giao diện HttpClient.
  • Chức năng thiết yếu nhất của HttpClient là thực thi các phương thức HTTP.
  • Việc thực thi một phương thức HTTP liên quan đến một hoặc một số trao đổi yêu cầu HTTP / phản hồi HTTP, thường được xử lý nội bộ bởi HttpClient.

  • ClosableHttpClient là một lớp trừu tượng là lớp triển khai cơ sở của HttpClient cũng thực thi java.io.Closable.
  • Đây là một ví dụ về quy trình thực thi yêu cầu ở dạng đơn giản nhất của nó:

    ClosableHttpClient httpclient = HttpClients.createDefault ();
    HttpGet httpget = new HttpGet ("http: // localhost /");
    Phản hồi của ClosableHttpResponse = httpclient.execute (httpget);
    thử {
        //làm việc gì đó
    } cuối cùng {
        response.close ();
    }

  • Phân bổ tài nguyên HttpClient: Khi một phiên bản ClosableHttpClient không còn cần thiết nữa và sắp vượt ra khỏi phạm vi, trình quản lý kết nối liên kết với nó phải được tắt bằng cách gọi phương thức ClosableHttpClient # close ().

    ClosableHttpClient httpclient = HttpClients.createDefault ();
    thử {
        //làm việc gì đó
    } cuối cùng {
        httpclient.close ();
    }

xem Tham khảo để tìm hiểu các nguyên tắc cơ bản.


@Scadge Kể từ Java 7, việc sử dụng câu lệnh try-with-resources đảm bảo rằng mỗi tài nguyên được đóng ở cuối câu lệnh. Nó có thể được sử dụng cho cả khách hàng và cho mỗi phản hồi

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
Câu trả lời này đặt ra câu hỏi. Việc gọi close () trên HttpClient khiến điều gì xảy ra mà nếu không sẽ xảy ra? Bạn có bị rò rỉ kết nối nếu bạn không gọi close () vào những thời điểm / địa điểm thích hợp không? Việc gọi close () sớm có ảnh hưởng đến hiệu suất của bạn bằng cách khiến bạn kết nối lại khi thực sự không cần thiết không?
gilbertpilz

4
Tôi đã xem qua mã trong httpclient để tìm câu trả lời cho câu hỏi này. Câu trả lời là phương pháp đóng được sử dụng để đóng trạng thái bên trong. Một số triển khai của HTTPClient (trong httpclient lib) có thể được định cấu hình để sử dụng các tài nguyên liên tục như PooledHttpClientConnectionManager cho các kết nối được gộp chung và nếu không có phương pháp này, bạn không thể dọn dẹp các tài nguyên này nếu cần.
Deadron

@SugarPudi trong ví dụ trên, chúng ta cần phải đóng httpgetcũng
Kasun Siyambalapitiya

Làm cách nào chúng ta có thể gọi các phương thức trên lớp trừu tượng (ClosableHttpClient) ở đây? Chúng ta không nên tạo một lớp con cụ thể trước?
illcar

@illcar hãy đi throuth câu trả lời này để hiểu được khái niệm stackoverflow.com/a/4321402/2830834
Sagar Pudi

26

Có cùng một câu hỏi. Các câu trả lời khác dường như không giải quyết được lý do tại sao close () lại thực sự cần thiết? Ngoài ra, Op dường như đang đấu tranh để tìm ra cách ưu tiên để làm việc với HttpClient, et al.


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

Ngoài ra, các mối quan hệ diễn ra như sau:

HttpClient (giao diện)

thực hiện bởi:

CloseableHttpClient - ThreadSafe.

DefaultHttpClient- ThreadSafe NHƯNG không dùng nữa , hãy sử dụng HttpClientBuilderthay thế.

HttpClientBuilder- KHÔNG phải ThreadSafe, NHƯNG tạo ra ThreadSafe CloseableHttpClient.

  • Sử dụng để tạo TÙY CHỈNH CloseableHttpClient.

HttpClients- KHÔNG phải ThreadSafe, NHƯNG tạo ra ThreadSafe CloseableHttpClient.

  • Sử dụng để tạo DEFAULT hoặc MINIMAL CloseableHttpClient.

Cách ưa thích theo Apache:

CloseableHttpClient httpclient = HttpClients.createDefault();

Ví dụ mà họ đưa ra có httpclient.close()trong finallymệnh đề, và cũng có thể sử dụng ResponseHandler.


Thay vào đó, cách mkyong làm cũng hơi thú vị:

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

Anh ấy không hiển thị một client.close()cuộc gọi nhưng tôi nghĩ nó là cần thiết, vì clientvẫn là một ví dụ của CloseableHttpClient.


15

Các câu trả lời khác dường như không giải quyết được tại sao lại close()thực sự cần thiết? * 2

Nghi ngờ về câu trả lời "Phân bổ tài nguyên HttpClient".

Nó được đề cập trong tài liệu httpcomponents 3.x cũ , lâu đời và có nhiều khác biệt với 4.x HC. Bên cạnh đó, lời giải thích quá ngắn gọn không cho biết tài nguyên cơ bản này là gì.

Tôi đã thực hiện một số nghiên cứu về mã nguồn phát hành 4.5.2, nhận thấy việc triển khai về CloseableHttpClient:close()cơ bản chỉ đóng trình quản lý kết nối của nó.

(FYI) Đó là lý do tại sao khi bạn sử dụng ứng dụng khách dùng chung PoolingClientConnectionManagervà gọi close(), ngoại lệ java.lang.IllegalStateException: Connection pool shut downsẽ xảy ra. Để tránh, setConnectionManagerSharedhoạt động.

Tôi không muốn làm CloseableHttpClient:close()sau mỗi yêu cầu

Tôi đã từng tạo một phiên bản máy khách http mới khi thực hiện yêu cầu và cuối cùng đóng nó. Trong trường hợp này, tốt hơn là không nên gọi close(). Vì nếu trình quản lý kết nối không có cờ "shared", nó sẽ bị tắt, quá đắt cho một yêu cầu.

Trên thực tế, tôi cũng tìm thấy trong thư viện clj-http , một trình bao bọc Clojure trên Apache HC 4.5, hoàn toàn không gọi close(). Xem func requesttrong tệp core.clj


1
Bạn có thể giải thích lý do tại sao nó tốt hơn là sử dụng setConnectionManagerShared và gọi close () sau mỗi yêu cầu?
zyfo2

9

Trong phiên bản chính tiếp theo của HttpClientgiao diện thư viện sẽ được mở rộng Closeable. Cho đến lúc đó, bạn nên sử dụng CloseableHttpClientnếu không yêu cầu khả năng tương thích với các phiên bản 4.x trước đó (4.0, 4.1 và 4.2).


8

HttpClientkhông phải là một lớp, nó là một giao diện. Bạn không thể sử dụng nó để phát triển theo cách của bạn.

Những gì bạn muốn là một lớp thực thi HttpClientgiao diện và đó là CloseableHttpClient.


2

CloseableHttpClientlà lớp cơ sở của thư viện httpclient, lớp mà tất cả các triển khai đều sử dụng. Phần lớn các lớp con khác không được dùng nữa.

Đây HttpClientlà một giao diện cho lớp này và các lớp khác.

Sau đó, bạn nên sử dụng CloseableHttpClientmã của mình và tạo nó bằng cách sử dụng HttpClientBuilder. Nếu bạn cần bọc ứng dụng khách để thêm hành vi cụ thể, bạn nên sử dụng các trình đánh chặn yêu cầu và phản hồi thay vì gói bằng HttpClient.

Câu trả lời này được đưa ra trong ngữ cảnh của httpclient-4.3.


0

Jon xiên nói:

Tài liệu có vẻ khá rõ ràng đối với tôi: "Triển khai cơ sở của HttpClient cũng triển khai Closable" - HttpClient là một giao diện; ClosableHttpClient là một lớp trừu tượng, nhưng vì nó triển khai AutoClosable nên bạn có thể sử dụng nó trong câu lệnh try-with-resources.

Nhưng sau đó Jules hỏi:

@JonSkeet Rõ ràng là vậy, nhưng đóng các phiên bản HttpClient quan trọng như thế nào? Nếu nó quan trọng, tại sao phương thức close () không phải là một phần của giao diện cơ bản?

Câu trả lời cho Jules

Đóng không cần phải là một phần của giao diện cơ bản vì kết nối cơ bản được giải phóng trở lại trình quản lý kết nối tự động sau mỗi lần thực thi

Để phù hợp với câu lệnh try-with-resources. Bắt buộc phải triển khai Closable. Do đó đã đưa nó vào ClosableHttpClient .

Ghi chú:

phương thức đóng trong AbstractHttpClient đang mở rộng ClosableHttpClient không được dùng nữa, tôi không thể tìm thấy mã nguồn cho điều đó.


Điều này dường như vẫn chưa trả lời được "tầm quan trọng của việc đóng các phiên bản HttpClient như thế nào?"
Vivek Chavda
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.