项目共存两个版本Amazon Kinesis Client的冲突问题求助
问题本质
你遇到的核心问题是:software.amazon.kinesis:amazon-kinesis-client:2.5.0(新版Kinesis客户端,groupId已迁移)和com.amazonaws:amazon-kinesis-client:1.14.9(旧版客户端,由Spring Cloud Stream Kinesis Binder 3.0.0传递引入)虽然groupId不同,但属于同一款客户端的新旧迭代版本,核心类(如Worker、RecordProcessor)的全限定类名完全一致。JVM类加载机制会优先加载其中一个版本的类,导致另一版本的代码因类不兼容或方法缺失完全失效,这就是旧消费流停止且无报错的原因。
可行解决方案
1. 类加载隔离(推荐,无需拆分应用)
通过构建工具的重定位(Relocate)功能,将旧版Kinesis客户端及其依赖的AWS类重命名到独立的包下,让新版客户端和重命名后的旧版客户端在类路径上完全隔离,互不干扰。
Maven Shade插件配置示例
在项目的pom.xml中添加Shade插件配置,专门对Spring Cloud Stream Binder及其依赖的旧版AWS库进行类重定位:
<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <version>3.4.1</version> <executions> <execution> <phase>package</phase> <goals> <goal>shade</goal> </goals> <configuration> <!-- 重定位旧版AWS类到自定义包 --> <relocations> <relocation> <pattern>com.amazonaws.services.kinesis</pattern> <shadedPattern>your.project.shaded.com.amazonaws.services.kinesis</shadedPattern> </relocation> <relocation> <pattern>com.amazonaws.auth</pattern> <shadedPattern>your.project.shaded.com.amazonaws.auth</shadedPattern> </relocation> <relocation> <pattern>com.amazonaws.handlers</pattern> <shadedPattern>your.project.shaded.com.amazonaws.handlers</shadedPattern> </relocation> <!-- 按需添加其他旧版AWS相关包的重定位 --> </relocations> <!-- 指定需要处理的依赖 --> <artifactSet> <includes> <include>org.springframework.cloud:spring-cloud-stream-binder-kinesis</include> <include>com.amazonaws:amazon-kinesis-client</include> <include>com.amazonaws:aws-java-sdk-kinesis</include> <include>com.amazonaws:aws-java-sdk-core</include> </includes> </artifactSet> </configuration> </execution> </executions> </plugin> </plugins> </build>
配置完成后,构建出的Jar包中,Spring Cloud Stream Binder会使用重命名后的旧版Kinesis类,而你的旧代码依然使用新版software.amazon.kinesis下的类,两者完全隔离,不会再出现类冲突。
2. 拆分模块为独立应用
将依赖新版Kinesis客户端的旧代码和依赖Spring Cloud Stream Binder的新代码拆分为两个独立的Spring Boot应用,通过中间件(如RabbitMQ、Redis)或HTTP接口实现进程间通信:
- 旧应用:专注于Kinesis流消费(使用
software.amazon.kinesis:amazon-kinesis-client:2.5.0),处理完成后将数据发送到中间件。 - 新应用:通过Spring Cloud Stream Binder消费中间件的数据,完成后续业务逻辑。
这个方案完全避免了类路径冲突,无需修改现有代码逻辑,但需要额外部署和维护两个应用,增加了运维成本。
3. 手动适配API(复杂度较高)
排除Binder传递的旧版Kinesis依赖,然后编写适配层,将新版Kinesis客户端的API包装成旧版API的形式,让Binder可以正常调用:
- 先排除旧版依赖:
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-stream-binder-kinesis</artifactId> <version>3.0.0</version> <exclusions> <exclusion> <groupId>com.amazonaws</groupId> <artifactId>amazon-kinesis-client</artifactId> </exclusion> <exclusion> <groupId>com.amazonaws</groupId> <artifactId>aws-java-sdk-kinesis</artifactId> </exclusion> </exclusions> </dependency>
- 编写适配类:比如针对旧版
Worker类,实现一个适配类,内部调用新版ScheduledExecutorServiceWorker的方法,模拟旧版API的行为。
这个方案需要深入理解Binder的内部实现逻辑,适配成本较高,适合对Kinesis客户端和Spring Cloud Stream Binder有较深了解的场景。
内容的提问来源于stack exchange,提问作者Lucas1983

