使用AWS Java SDK 2.0的WebIdentityTokenFileCredentialsProvider遇SdkClientException
问题
我有一个基于Kinesis正常运行的应用,原本使用AWS会话凭证,现需根据部署环境切换为AWS会话凭证或Web Identity Token(software.amazon.awssdk.auth.credentials.WebIdentityTokenFileCredentialsProvider)。添加使用该凭证提供者的代码后出现如下错误堆栈:
导致错误的原因:software.amazon.awssdk.core.exception.SdkClientException:类路径上发现多个HTTP实现。为避免非确定性加载实现,请通过客户端构建器显式提供HTTP客户端,设置software.amazon.awssdk.http.service.impl系统属性指定默认使用的HTTP服务的全限定类名,或移除类路径中除一个外的所有HTTP实现 at software.amazon.awssdk.core.exception.SdkClientException$BuilderImpl.build(SdkClientException.java:102) at software.amazon.awssdk.core.internal.http.loader.ClasspathSdkHttpServiceProvider.loadService(ClasspathSdkHttpServiceProvider.java:62) at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) at java.base/java.util.Spliterators$ArraySpliterator.tryAdvance(Spliterators.java:1002) at java.base/java.util.stream.ReferencePipeline.forEachWithCancel(ReferencePipeline.java:129) at java.base/java.util.stream.AbstractPipeline.copyIntoWithCancel(AbstractPipeline.java:527) at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:513) at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499) at java.base/java.util.stream.FindOps$FindOp.evaluateSequential(FindOps.java:150) at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) at java.base/java.util.stream.ReferencePipeline.findFirst(ReferencePipeline.java:647) at software.amazon.awssdk.core.internal.http.loader.SdkHttpServiceProviderChain.loadService(SdkHttpServiceProviderChain.java:44) at software.amazon.awssdk.core.internal.http.loader.CachingSdkHttpServiceProvider.loadService(CachingSdkHttpServiceProvider.java:46) at software.amazon.awssdk.core.internal.http.loader.DefaultSdkHttpClientBuilder.buildWithDefaults(DefaultSdkHttpClientBuilder.java:40) at software.amazon.awssdk.core.client.builder.SdkDefaultClientBuilder.lambda$resolveSyncHttpClient$7(SdkDefaultClientBuilder.java:343) at java.base/java.util.Optional.orElseGet(Optional.java:364) at software.amazon.awssdk.core.client.builder.SdkDefaultClientBuilder.resolveSyncHttpClient(SdkDefaultClientBuilder.java:343) at software.amazon.awssdk.core.client.builder.SdkDefaultClientBuilder.finalizeSyncConfiguration(SdkDefaultClientBuilder.java:282) at software.amazon.awssdk.core.client.builder.SdkDefaultClientBuilder.syncClientConfiguration(SdkDefaultClientBuilder.java:178) at software.amazon.awssdk.services.sts.DefaultStsClientBuilder.buildClient(DefaultStsClientBuilder.java:27) at software.amazon.awssdk.services.sts.DefaultStsClientBuilder.buildClient(DefaultStsClientBuilder.java:22) at software.amazon.awssdk.core.client.builder.SdkDefaultClientBuilder.build(SdkDefaultClientBuilder.java:145) at software.amazon.awssdk.services.sts.internal.StsWebIdentityCredentialsProviderFactory$StsWebIdentityCredentialsProvider.<init>(StsWebIdentityCredentialsProviderFactory.java:71) at software.amazon.awssdk.services.sts.internal.StsWebIdentityCredentialsProviderFactory$StsWebIdentityCredentialsProvider.<init>(StsWebIdentityCredentialsProviderFactory.java:55) at software.amazon.awssdk.services.sts.internal.StsWebIdentityCredentialsProviderFactory.create(StsWebIdentityCredentialsProviderFactory.java:47) at software.amazon.awssdk.auth.credentials.WebIdentityTokenFileCredentialsProvider.<init>(WebIdentityTokenFileCredentialsProvider.java:86) at software.amazon.awssdk.auth.credentials.WebIdentityTokenFileCredentialsProvider.<init>(WebIdentityTokenFileCredentialsProvider.java:46) at software.amazon.awssdk.auth.credentials.WebIdentityTokenFileCredentialsProvider$BuilderImpl.build(WebIdentityTokenFileCredentialsProvider.java:200)
解决方案
1. 设置系统属性指定默认HTTP实现
直接配置software.amazon.awssdk.http.service.impl系统属性,指定你项目中要使用的HTTP客户端全限定类名:
- 若使用Apache HttpClient:
software.amazon.awssdk.http.apache.ApacheSdkHttpService - 若使用URL Connection:
software.amazon.awssdk.http.urlconnection.UrlConnectionSdkHttpService
可以通过JVM启动参数设置:
-Dsoftware.amazon.awssdk.http.service.impl=software.amazon.awssdk.http.apache.ApacheSdkHttpService
也能在代码初始化阶段设置:
System.setProperty("software.amazon.awssdk.http.service.impl", "software.amazon.awssdk.http.apache.ApacheSdkHttpService");
2. 清理依赖,仅保留一个HTTP客户端实现
检查项目依赖树,移除多余的AWS SDK HTTP客户端依赖。比如如果已经引入了aws-sdk-apache-client,就删除aws-sdk-url-connection-client依赖,反之亦然,确保类路径中只有一个HTTP实现。
3. 自定义STS客户端传入凭证提供者
WebIdentityTokenFileCredentialsProvider内部会创建STS客户端来获取临时凭证,你可以预先配置好和Kinesis客户端一致的HTTP客户端,构建自定义STS客户端后传入凭证提供者:
// 复用你已经为Kinesis配置好的HTTP客户端 SdkHttpClient httpClient = ...; // 构建带指定HTTP客户端的STS客户端 StsClient stsClient = StsClient.builder() .httpClient(httpClient) .build(); // 构建WebIdentity凭证提供者时传入自定义STS客户端 WebIdentityTokenFileCredentialsProvider credentialsProvider = WebIdentityTokenFileCredentialsProvider.builder() .stsClient(stsClient) .build(); // 将凭证提供者传给Kinesis客户端 KinesisClient kinesisClient = KinesisClient.builder() .credentialsProvider(credentialsProvider) .httpClient(httpClient) .build();
这种方式能让STS客户端复用你已有的HTTP配置,避免SDK自动加载时触发多实现冲突。
内容的提问来源于stack exchange,提问作者cwa
相关产品推荐
相关产品推荐

