Maven同模块安装使用同一artifact多版本的可行方案咨询
Maven默认依赖调解机制会在同一模块的依赖树中仅保留单个版本的同坐标artifact,直接声明两个版本会导致其中一个被自动剔除,就算手动把两个版本的jar塞入类路径,也会因为类全限定名重复触发类加载冲突,以下是经过生产验证的可落地方案:
方案1:使用
maven-shade-plugin重定位其中一个版本的包路径(生产环境首选)
这个方案的核心是修改其中一个版本依赖的字节码,将其原有包路径重命名为自定义的独立路径,让两个版本的类全限定名完全不重复,JVM会把两者识别为完全独立的类,不会产生任何冲突。
插件配置参考如下,示例中对1.0.0版本的com.example:target-lib做重定位处理:<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <version>3.5.1</version> <executions> <execution> <phase>package</phase> <goals> <goal>shade</goal> </goals> <configuration> <relocations> <relocation> <pattern>com.example.targetlib</pattern> <shadedPattern>com.yourproject.shaded.targetlib.v1</shadedPattern> <artifactInclude>com.example:target-lib:1.0.0</artifactInclude> </relocation> </relocations> </configuration> </execution> </executions> </plugin>配置完成后执行Maven打包,v1版本的所有类都会被自动迁移到
com.yourproject.shaded.targetlib.v1包下,代码中导入这个新路径下的类即可使用v1版本能力;v2版本保留原包名正常导入即可,两者完全隔离互不影响。注意:如果被重定位的依赖用到了SPI机制、或者代码中存在硬编码的全限定类名字符串,需要额外配置shade插件的资源转换器、字符串替换规则,避免运行时出现服务找不到、类初始化失败的问题。
方案2:自定义类加载器做隔离(仅适合特殊场景)
如果不想修改依赖的字节码,可以通过自定义类加载器打破双亲委派机制,用两个完全独立的类加载器分别加载两个版本的jar包。注意两个版本的类调用逻辑必须完全在各自类加载器的上下文内完成,禁止跨类加载器传递同全限定名的类对象,否则会抛出ClassCastException。
这个方案实现成本高、调试难度大,仅适合两个版本逻辑完全隔离、没有交叉调用的场景,普通业务场景不推荐使用。
避坑提示
不要尝试直接在pom.xml中声明两个版本的同坐标依赖,Maven不会同时将两个版本加入编译/运行类路径,最终只会生效声明顺序靠前、或者依赖路径更短的那个版本,另一个版本的类会直接报编译找不到类的错误。
内容的提问来源于stack exchange,提问作者sacp

