Java 21+Spring Boot 3环境下AWS Lambda重复创建S3Client引发IdentityProperty重复冲突的解决方法咨询
我最近在Java 21 + Spring Boot 3的环境下开发AWS Lambda,遇到了一个和S3 Client相关的诡异问题,想请教各位大佬怎么解决。
先介绍下我的配置:我的Lambda需要用到S3客户端,所以写了这样一个配置类:
@Configuration public class AwsConfig { @Bean public S3Client awsS3Client() { return S3Client.builder() .region(Region.US_WEST_2) .build(); } }
问题表现
当我连续多次触发这个Lambda的时候,AWS环境似乎会在之前的S3Client实例被垃圾回收前就创建新的实例,直接抛出了如下错误:
No duplicate IdentityProperty names allowed but both IdentityProperties 7890fbf9 and 25f0f461 have the same namespace (java.lang.String) and name (Bucket). IdentityProperty should be referenced from a shared static constant to protect against erroneous or unexpected collisions.
但奇怪的是,如果我间隔5-7分钟再去触发Lambda,一切又能正常运行,完全没问题!
调试后的根源分析
我跟进了AWS SDK的源码,发现这个错误来自IdentityProperty类。这个类里维护了一个静态的并发集合,用来记录已经注册过的属性:
private static final ConcurrentMap<Pair<String, String>, IdentityProperty<?>> NAME_HISTORY = new ConcurrentHashMap<>(); private void ensureUnique() { IdentityProperty<?> prev = NAME_HISTORY.putIfAbsent(Pair.of(namespace, name), this); Validate.isTrue(prev == null, "No duplicate IdentityProperty names allowed but both IdentityProperties %s and %s have the same " + "namespace (%s) and name (%s). IdentityProperty should be referenced from a shared static constant to " + "protect against erroneous or unexpected collisions.", Integer.toHexString(System.identityHashCode(prev)), Integer.toHexString(System.identityHashCode(this)), namespace, name); }
问题出在这个NAME_HISTORY是静态变量,第一次Lambda调用后,这个集合并没有被清空。后续调用Lambda时,新创建的S3Client会尝试注册同一个"java.lang.String"/"Bucket"键,而集合里已经存在这个键了,所以触发了校验失败的错误。这个校验逻辑是被S3ExpressAuthSchemeProvider调用的,最终由DefaultS3ClientBuilder触发执行。
我已经尝试过的方案(均无效)
- 将S3Client声明为类的静态成员变量
- 给S3Client的Bean加上
@Scope("prototype")(临时hack,但没解决问题) - 用反射强行清空
NAME_HISTORY集合,结果又出现了其他属性的重复冲突错误 - 调整各种Bean的生命周期和实例化策略,比如尝试用
@Lazy等,都没效果
想请教大家,有没有什么靠谱的方法能解决这个问题?怎么才能让Lambda连续多次调用时,不会触发这个IdentityProperty的重复冲突呢?
内容来源于stack exchange

