2022-06-14 11:02:21
包含依赖:将所有传递性依赖的.class文件直接复制到主JAR包中。
重定位包(Relocation):解决依赖冲突的关键机制,可将依赖的包名重命名(如将com.google.common.base重命名为com.yourproject.shaded.guava.common.base),使不同版本的同名类因包名不同而不直接冲突。
接口/类实现不匹配:编译时期望类实现某接口,但运行时加载的类版本未实现该接口,或实现的是不同版本接口。
字段或方法签名不匹配:编译时引用的字段或方法在运行时加载的类中不存在或签名不一致。
WAR包结构分析:对于Web应用程序,检查WEB-INF/lib目录。例如,若存在以下文件:
WEB-INF/lib/java-driver-shaded-guava-25.1-jre-graal-sub-1.jar.d/com/datastax/oss/driver/shaded/guava/common/base/Suppliers$MemoizingSupplier.class
WEB-INF/lib/nautilus-es2-library-2.3.4.jar.d/com/google/common/base/Suppliers$MemoizingSupplier.class
WEB-INF/lib/guava-30.1.1-jre.jar.d/com/google/common/base/Suppliers$MemoizingSupplier.class则表明存在三个不同来源的Guava类,其中nautilus-es2-library-2.3.4.jar和guava-30.1.1-jre.jar中的com.google.common.base.Suppliers$MemoizingSupplier全限定名相同,是冲突根源。
使用jar tf命令:检查特定JAR文件中包含的类,如jar tf your-library.jar | grep Suppliers$MemoizingSupplier.class。
JVM参数:启动JVM时添加-verbose:class参数,输出所有类加载的详细信息,追踪类文件被哪个类加载器加载。
IDE工具:现代IDE(如IntelliJ IDEA)提供依赖分析工具,可直观显示冲突。
分析Shaded Jar的来源:确定包含冲突依赖的库(如nautilus-es2-library-2.3.4.jar)为何包含该依赖,理想情况下库应声明依赖而非打包。
排除策略:若库不应包含依赖或其依赖与应用程序冲突,可在构建配置中排除。Maven示例:
使用BOM (Bill of Materials):大型项目可使用Spring Boot或Google Cloud等提供的BOM管理和统一常用库版本。
Maven的dependencyManagement:在父POM中声明dependencyManagement部分,集中管理依赖版本,确保子模块使用统一版本。示例:
Shaded Jar作者:确保对内部依赖进行适当包重定位。
Shaded Jar使用者:若无法修改其内容,需依赖排除或统一版本来解决冲突。