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
。所以我认为CloseableHttpClient
是HttpClient
的扩展版本。如果是这种情况,我有两个问题:
【问题讨论】:
文档对我来说似乎很清楚:“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,而是创建 ThreadSafeCloseableHttpClient
。用于创建 CUSTOMCloseableHttpClient
。
HttpClients
- 不是 ThreadSafe,而是创建 ThreadSafeCloseableHttpClient
。用于创建 DEFAULT 或 MINIMALCloseableHttpClient
。
根据 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的使用
Android API 23 - HttpClient 4.X 重新打包