Apache HttpClient API 中的 CloseableHttpClient 和 HttpClient 有啥区别?

Posted

技术标签:

【中文标题】Apache HttpClient API 中的 CloseableHttpClient 和 HttpClient 有啥区别?【英文标题】:What is the difference between CloseableHttpClient and HttpClient in Apache HttpClient API?Apache HttpClient API 中的 CloseableHttpClient 和 HttpClient 有什么区别? 【发布时间】:2014-03-01 17:17:26 【问题描述】:

我正在研究我们公司开发的应用程序。它使用 Apache HttpClient 库。在源代码中,它使用HttpClient 类来创建实例以连接到服务器。

我想了解 Apache HttpClient,我已经了解了this set of examples。所有示例都使用CloseableHttpClient 而不是HttpClient。所以我认为CloseableHttpClientHttpClient 的扩展版本。如果是这种情况,我有两个问题:

这两者有什么区别? 建议在我的新开发中使用哪个类?

【问题讨论】:

文档对我来说似乎很清楚:“HttpClient 的基本实现也实现了 Closeable” - HttpClient 是一个接口; CloseableHttpClient 是一个抽象类,但由于它实现了 AutoCloseable,您可以在 try-with-resources 语句中使用它。 @JonSkeet 这很清楚,但关闭HttpClient 实例有多重要?如果它很重要,为什么close() 方法不是基本接口的一部分? @Jules: 恐怕我对 HttpClient 了解的不够多,无法回答这个问题:( 关闭不需要是基本接口的一部分,因为底层连接会自动释放回连接管理器 【参考方案1】: 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 响应 = httpclient.execute(httpget);
尝试 
    //做一点事
 最后 
    response.close();

HttpClient 资源释放: 当不再需要某个实例 CloseableHttpClient 并且即将超出范围时,必须通过调用 CloseableHttpClient#close() 方法来关闭与其关联的连接管理器。

CloseableHttpClient httpclient = HttpClients.createDefault();
尝试 
    //做一点事
 最后 
    httpclient.close();

请参阅Reference 了解基础知识。


@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

【讨论】:

这个答案有点引人入胜。在 HttpClient 上调用 close() 会导致什么情况下不会发生?如果您不在适当的时间/地点调用 close(),您是否会泄漏连接?调用 close() 是否会在您确实不需要时重新连接,从而过早影响您的性能? 我查看了 httpclient 中的代码来寻找这个问题的答案。答案是 close 方法用于关闭内部状态。 HTTPClient 的一些实现(在 httpclient 库中)可以配置为使用持久性资源,例如 PooledHttpClientConnectionManager 用于池连接,如果没有这种方法,您将无法在需要时清理这些资源。 上例中的@SugarPudi,是否也需要关闭httpget 我们如何在这里调用抽象类(CloseableHttpClient)上的方法?我们不应该先创建一个具体的子类吗? @illcar 请通过这个答案来理解***.com/a/4321402/2830834这个概念【参考方案2】:

乔恩·斯基特说:

文档对我来说似乎很清楚:“也实现 Closeable 的 HttpClient 的基本实现” - HttpClient 是一个接口; CloseableHttpClient 是一个抽象类,但由于它实现了 AutoCloseable,您可以在 try-with-resources 语句中使用它。

但随后朱尔斯问道:

@JonSkeet 很清楚,但是关闭 HttpClient 实例有多重要?如果很重要,为什么 close() 方法不是基本接口的一部分?

朱尔斯的答案

close 不需要是基本接口的一部分,因为底层连接 每次执行后自动释放回连接管理器

为了适应 try-with-resources 语句。必须实现 Closeable。因此将其包含在 CloseableHttpClient 中。

注意:

扩展 CloseableHttpClient 的 AbstractHttpClient 中的 close 方法已弃用,我无法找到它的源代码。

【讨论】:

这似乎仍然没有回答“关闭 HttpClient 实例有多重要?” 这个答案意味着您根本不必关闭 HttpClient 实例,这反过来意味着 CloseableHttpClient 只是一个错误。【参考方案3】:

有同样的问题。其他答案似乎没有解决为什么真的需要 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 - 线程安全。

DefaultHttpClient - ThreadSafe 但deprecated,改用HttpClientBuilder

HttpClientBuilder - 不是 ThreadSafe,而是创建 ThreadSafe CloseableHttpClient

用于创建 CUSTOM CloseableHttpClient

HttpClients - 不是 ThreadSafe,而是创建 ThreadSafe CloseableHttpClient

用于创建 DEFAULT 或 MINIMAL CloseableHttpClient

根据 Apache 的首选方式:

CloseableHttpClient httpclient = HttpClients.createDefault();

The example 他们在finally 子句中给出了httpclient.close(),并且还使用了ResponseHandler


作为替代方案,mkyong 的做法也有点有趣:

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

他没有显示client.close() 调用,但我认为这是必要的,因为client 仍然是CloseableHttpClient 的一个实例。

【讨论】:

【参考方案4】:

其他答案似乎没有解决为什么close() 真的有必要? * 2

对“HttpClient 资源释放”的回答存疑。

在旧的3.x httpcomponentsdoc中提到过,它由来已久,与4.x HC有很大的不同。此外,解释很简短,没有说明这个底层资源是什么。

我对4.5.2版本源代码做了一些研究,发现CloseableHttpClient:close()的实现基本上只是关闭了它的连接管理器。

(仅供参考)这就是为什么当您使用共享 PoolingClientConnectionManager 并调用客户端 close() 时,会发生异常 java.lang.IllegalStateException: Connection pool shut down。为避免,setConnectionManagerShared 有效。

我更喜欢在每次请求后都做CloseableHttpClient:close()

我曾经在请求时创建一个新的http客户端实例,最后关闭它。在这种情况下,最好不要拨打close()。因为,如果连接管理器没有“共享”标志,它将被关闭,这对于单个请求来说太昂贵了。

事实上,我还在库 clj-http 中发现,它是 Apache HC 4.5 上的 Clojure 包装器,根本不调用 close()。参见文件core.clj中的funcrequest

【讨论】:

你能解释一下为什么它比使用 setConnectionManagerShared 并在每次请求后调用 close() 更好吗?【参考方案5】:

HttpClient 不是一个类,它是一个接口。您不能按照您的意思将其用于开发。

你想要的是一个实现HttpClient接口的类,那就是CloseableHttpClient

【讨论】:

【参考方案6】:

CloseableHttpClient 是 httpclient 库的基类,所有实现都使用它。其他子类大部分已弃用。

HttpClient 是这个类和其他类的接口。

然后您应该在代码中使用CloseableHttpClient,并使用HttpClientBuilder 创建它。如果您需要包装客户端以添加特定行为,您应该使用请求和响应拦截器,而不是使用 HttpClient 包装。

这个答案是在 httpclient-4.3 的上下文中给出的。

【讨论】:

【参考方案7】:

在库HttpClient 的下一个主要版本中,接口将扩展Closeable。在此之前,如果不需要与早期 4.x 版本(4.0、4.1 和 4.2)兼容,建议使用 CloseableHttpClient

【讨论】:

历史说你错了,因为我们在 v5.1 并且 HttpClient 仍然没有扩展 Closeable hc.apache.org/httpcomponents-client-5.1.x/current/httpclient5/…

以上是关于Apache HttpClient API 中的 CloseableHttpClient 和 HttpClient 有啥区别?的主要内容,如果未能解决你的问题,请参考以下文章

忽略 Apache HttpClient 4.3 中的 SSL 证书

Apache HttpClient之fluent API的使用

Apache HttpClient 读取响应乱码问题总结

Android API 23 - HttpClient 4.X 重新打包

Android 已弃用 apache 模块(HttpClient、HttpResponse 等)

android和httpClient