我正在使用 Java SDK v2 中的 S3Client。在分布式 Web 应用程序中从 AWS S3 上传/下载文件。
我遇到了
idle-connection-reaper
守护线程阻止/延迟关闭期间卸载类的问题。我做了一些调查,发现在 AWS Java SDK v1 中,可以通过调用 IdleConnectionReaper.shutdown()
方法来解决这个问题。
我将apache客户端导入到我的项目中
<!-- https://mvnrepository.com/artifact/software.amazon.awssdk/apache-client -->
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>apache-client</artifactId>
<version>2.17.162</version>
</dependency>
我想使用 AWS Java SDK v2 做同样的事情。问题是
shutdown()
方法不再是静态和公开的。
他们将类更改为 Singleton,唯一公开的 API 是:
public synchronized boolean registerConnectionManager(HttpClientConnectionManager manager, long maxIdleTime)
public synchronized boolean deregisterConnectionManager(HttpClientConnectionManager manager)
deregisterConnectionManager()
在内部调用 shutdown,但我不知道什么 HttpClientConnectionManager
我应该作为这两种方法的参数给出
我的问题是:是否有另一种方法可以关闭该守护线程,或者我应该坚持使用
IdleConnectionReaper
的新实现?如果是这样,HttpClientConnectionManager
和registerConnectionManager
方法中的deregisterConnectionManager
参数到底是什么?
IdleConnectionReaper
进行交互,这就是公共界面已更改以反映这一点的原因。
AWS Java SDK v1 和 v2 在 S3 客户端方面存在关键区别。
AmazonS3Client
实现了 AmazonS3
自定义接口,该接口提供了要实现的 shutdown
方法。
这不是强制执行的,而是一种可选方法,因此我假设需要守护线程来防止泄漏,以防 S3 客户端在任何地方都没有关闭。
S3Client
实现了AutoClosable
接口,这是版本7之后java.lang
中固有的接口。
通过
AutoClosable
,AWS SDK 清楚地传达了您的应用程序管理 S3 客户端的关闭和清理的期望。这最好通过将客户端的关闭委托给 JVM 来完成,方法是将其包含在 try-with-resources 语句中,或者如果需要,通过 S3Client.close()
显式地进行。
AWS Java SDK v2 利用 Java 语言的较新功能,因此,它希望您能够根据现代 Java 开发实践正确处理资源。
正确关闭您的 S3 客户端对象(和对象内容流!),一切都会好起来的。
更多分析: 内部 ReaperTask 有 1 分钟的睡眠时间,在此期间它不会检查其“停止”标志 - 因此它没有意识到它应该关闭。但是,一旦重新注册最后一个连接管理器,它将被中断/关闭。
我这边的问题是使用 SDK 构建器和注入的 HttpClient(也是由 SDK 构建器构建)。这会导致它周围有一个包装器,防止在外部客户端关闭时取消注册。
我们遇到了同样的问题,这是泄漏 IdleConnectionReaper 的代码。
return SsmClient.builder()
.credentialsProvider(provider)
.overrideConfiguration(builder -> builder.retryPolicy(
buildRetryPolicy(MAX_SSM_RETRIES)
))
.build();
问题是正在传递的提供者(
WebIdentityTokenFileCredentialsProvider
)也需要显式关闭。关闭 SDK 客户端不会关闭凭证提供程序本身内的 http 客户端。我们明确关闭了它,问题就消失了。