Maven项目反射调用触发的VirtualMachine类加载优先级冲突问题
Maven类加载冲突解决方案:让依赖1优先加载JDK提供的VirtualMachine类
核心原理
出现该问题的根本原因是全限定类名相同的情况下,类加载器会优先加载类路径上排序更靠前的Jar包中的类,依赖2的Jar包在类路径中的排序早于JDK的tools.jar(JDK9+对应jdk.attach模块),导致优先加载了依赖2内置的com.sun.tools.attach.VirtualMachine类。
可行方案
方案1:排除依赖2内置的attach包(优先推荐)
如果依赖2本身不需要使用它自带的com.sun.tools.attach包,直接在pom.xml中对依赖2添加排除规则即可,从根源避免冲突。
<dependency> <groupId>【替换为依赖2的实际groupId】</groupId> <artifactId>【替换为依赖2的实际artifactId】</artifactId> <version>【替换为依赖2的实际版本】</version> <exclusions> <exclusion> <groupId>【替换为依赖2中attach包的实际groupId】</groupId> <artifactId>【替换为依赖2中attach包的实际artifactId】</artifactId> </exclusion> </exclusions> </dependency>
配置完成后重新打包,依赖2内置的attach包不会被引入类路径,类加载器会自动加载JDK提供的对应类。
方案2:显式声明JDK tools.jar依赖并调整排序
如果无法排除依赖2的内置attach包,可以在pom.xml中显式声明JDK的tools.jar依赖,并且将该依赖的声明位置放在依赖2之前,利用Maven依赖声明顺序优先的规则,让JDK的类优先级更高。
JDK8及更早版本配置
<!-- 该依赖必须放在依赖2的声明之前 --> <dependency> <groupId>com.sun</groupId> <artifactId>tools</artifactId> <version>1.8</version> <scope>system</scope> <systemPath>${java.home}/../lib/tools.jar</systemPath> </dependency> <!-- 依赖2的声明放在tools.jar之后 --> <dependency> <groupId>依赖2的groupId</groupId> <artifactId>依赖2的artifactId</artifactId> <version>依赖2的版本</version> </dependency>
JDK9及以上版本配置
JDK9之后tools.jar被移除,com.sun.tools.attach相关类归属到jdk.attach模块,只需要在模块描述文件module-info.java中添加模块依赖即可:
module your.project.module { requires jdk.attach; }
同时保持JDK相关依赖的声明顺序早于依赖2即可。
方案3:自定义类加载器(适用于特殊场景)
如果依赖2本身必须使用它自带的com.sun.tools.attach包,无法做全局排除,可针对依赖1的ClassA所在的包自定义类加载器,打破双亲委派机制,优先加载JDK中的com.sun.tools.attach相关类,其余类依旧走正常的双亲委派逻辑。
该方案侵入性较高,仅在前两种方案无法落地时使用。
内容的提问来源于stack exchange,提问作者preetk
相关产品推荐
相关产品推荐

