java - 在单例中使用 Apache CloseableHttpClient 的风险
问题描述
我正在使用 Apache Http Client 4.5.3,目前正在重构一些代码。
目前我有一个单例 Util,它有几个方法,它们的职责是通过获取、帖子、补丁等来访问 API。以前,我们一直使用 an来为每个方法的每次调用HttpClientBuilder
构造一个对象。CloseableHttpClient
大致来说,Singleton 的架构是这样的:
import com.google.gson.Gson
import org.apache.http.client.methods.{HttpGet, HttpPost}
import org.apache.http.entity.StringEntity
import org.apache.http.impl.client.{CloseableHttpClient, HttpClientBuilder}
import org.apache.http.util.EntityUtils
import org.json4s.DefaultFormats
import org.json4s.jackson.JsonMethods.parse
object ApiCallerUtil {
case class StoreableObj(name:String, id:Long)
case class ResponseKey(key:Long)
def getKeyCall(param:String): ResponseKey = {
implicit val formats = DefaultFormats
val get = new HttpGet("http://wwww.someUrl.com/api/?value=" + param)
val client:CloseableHttpClient = HttpClientBuilder.create().build()
val response = client.execute(get)
try {
val entity = response.getEntity
val entityStr = EntityUtils.toString(entity)
parse(entityStr).extract[ResponseKey]
} finally {
response.close()
client.close()
}
}
def postNewObjCall(param:String, i:Long): Boolean = {
val post = new HttpPost(("http://wwww.someUrl.com/api/createNewObj"))
val client = HttpClientBuilder.create().build()
post.setHeader("Content-type", "application/json")
val pollAsJson = new Gson().toJson(StoreableObj(param, i))
post.setEntity(new StringEntity(pollAsJson))
val response = client.execute(post)
try {
if (response.getStatusLine.getStatusCode < 300) true else false
} finally {
response.close()
client.close()
}
}
//... and so on
}
关于如何使用它的注意事项 - 我们的系统中有许多类使用这个 Singleton Util 来调用 API。这个 Singleton 将经历短时间的大量使用,其中几个类会以高频率(在几分钟内高达 @1000 次),以及在很长一段时间内多次被击中的时间段(每小时一次或两次),或者一次几个小时都不做。此外,它点击的所有 URL 都将以相同的 URL 开头(例如www.someUrl.com/api/
)
但我想知道在val client = HttpClientBuilder.create().build
作为仅对象内可访问变量的私有 val 调用一次的地方实现它是否有意义。这样,它只会在对象实例化时创建一次。这是我暂停的地方,Apache 文档确实说了这两件事:
1.2.1。[Closeable]HttpClient 实现应该是线程安全的。建议将此类的同一个实例重复用于多个请求执行。
1.2.2。当不再需要 [Closeable]HttpClient 实例并且即将超出范围时,关闭其连接管理器以确保关闭管理器保持活动状态的所有连接并释放由这些连接分配的系统资源非常重要。
我已经阅读了大部分文档,但对以下问题没有明确的答案:
将 CloseableHttpClient 实例作为私有全局变量是否有任何风险?我担心如果某些东西过时可能会被关闭,并且我必须在一段时间后对其进行树脂验证,或者在大量使用的情况下,它会造成太多的瓶颈。根据上面的#1.2.2,变量将“永远”超出范围,因为它是一个单例对象。但是由于我只是构建客户端并在执行过程中将
HttpRequest
对象传递给它,而不是单独将其连接到请求之外的 API,因此这似乎无关紧要。由于这个
ApiCallerUtil
Singleton 的使用方式的性质,使用它们的HttpClientConnectionManager
or 是否是明智的。PoolingHttpClientConnectionManager
保持稳定的连接www.someUrl.com/api/
?性能提升值得吗?到目前为止,当前的实现似乎没有任何严重的性能缺陷。
感谢您的任何反馈!
解决方案
没有(基于我 15 年以上的 HttpClient 经验)。
这实际上取决于各种因素(TLS 会话握手的开销等)。我想人们真的想确保通过持久连接执行一系列相关请求。在长时间不活动期间,您可能希望从连接池中逐出所有空闲连接。这还有一个额外的好处,那就是减少遇到陈旧(半关闭)连接问题的机会。
推荐阅读
- c - 通过 C 中的库包装器自动进行函数重定向
- react-native - 修改 mapStateToProps 以实现通用访问
- apache-spark - Spark 按 Key 分组并对数据进行分区
- java - 从 JRE 7 或 8 升级到 JRE11 后,Java Swing JFrame 大小不同。如何使帧大小保持一致?
- asp.net-mvc - ASP.NET Core Razor Pages,有没有办法配置链接目录文件夹路径?
- perl - 从 tk perl 接口中的子例程传递变量
- r - 如何将日期放在 barplot() x 轴上?
- gitlab - GitLab-审稿人名单
- ruby-on-rails - puma 新的 fork-worker 选项,与 preload_app 的关系
- reactjs - 使用 React.useMemo 时不触发更新或无限循环