JPMS与外部JAR引发ResolutionException的通用解决方案咨询
针对JPMS模块包冲突的通用解决方案
一、临时规避:启动时指定模块版本优先级
JPMS本身没有直接的包优先级参数,但可以通过显式指定要使用的模块版本来让模块解析器优先选择目标模块,避免冲突。启动命令示例:
java --module-path lib:target/classes \ --add-modules com.tngtech.junit.dataprovider.core@[具体版本号] \ --limit-modules com.tngtech.junit.dataprovider.core,你的主模块 \ --module 你的主模块/主类全路径
--add-modules指定强制加载的模块及版本,优先级高于自动解析--limit-modules限制模块解析范围,减少冲突概率
二、重打包冲突模块(Maven环境)
如果冲突模块无法替换,可通过Maven插件重打包,移除冲突的包导出声明或删除重复包:
1. 使用maven-shade-plugin修改模块描述符
在Maven pom.xml中配置shade插件,修改冲突模块的module-info.java:
<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> <filters> <!-- 针对冲突的junit4模块,移除重复的包导出 --> <filter> <artifact>com.tngtech.junit.dataprovider:junit4-dataprovider</artifact> <transformers> <transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/> <transformer implementation="org.apache.maven.plugins.shade.resource.ModuleInfoResourceTransformer"> <!-- 删除向commons.logging导出com.tngtech.junit.dataprovider.resolver的声明 --> <moduleInfoFilter> <excludeExport>com.tngtech.junit.dataprovider.resolver->commons.logging</excludeExport> </moduleInfoFilter> </transformer> </transformers> </filter> </filters> </configuration> </execution> </executions> </plugin>
执行mvn package后,生成的shaded JAR会修改模块描述符,消除冲突。
2. 直接移除冲突包(如果重复包功能冗余)
如果两个模块的重复包功能完全一致,可通过shade插件删除其中一个模块的冲突包:
<filter> <artifact>com.tngtech.junit.dataprovider:junit4-dataprovider</artifact> <includes> <include>**/*</include> </includes> <excludes> <exclude>com/tngtech/junit/dataprovider/resolver/**</exclude> </excludes> </filter>
三、使用模块化JAR打包工具替代Eclipse导出
Eclipse的可运行JAR导出不支持JPMS的module-path启动,推荐使用以下工具生成可分发的模块化包:
- maven-jlink-plugin:生成自定义JRE镜像,自动处理模块依赖,避免冲突。配置示例:
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jlink-plugin</artifactId> <version>3.1.0</version> <executions> <execution> <phase>package</phase> <goals> <goal>jlink</goal> </goals> <configuration> <modulepath> <modulepath>${project.build.directory}/classes</modulepath> <modulepath>${maven.dependency.classpath}</modulepath> </modulepath> <launcher>app=你的主模块/主类全路径</launcher> <outputDirectory>${project.build.directory}/jlink-image</outputDirectory> </configuration> </execution> </executions> </plugin>
执行mvn package后,jlink-image目录下的bin/app可直接启动程序,无需手动处理module-path。
四、长期方案:隔离冲突模块
如果上述方法仍有问题,可将冲突模块放入**类路径(classpath)**而非模块路径,JPMS会优先加载模块路径的类,类路径的类作为自动模块处理,避免包导出冲突:
java --module-path lib/你的主模块.jar:lib/无冲突模块.jar \ --class-path lib/冲突模块1.jar:lib/冲突模块2.jar \ --module 你的主模块/主类全路径
注意:此方法仅适用于冲突模块不依赖JPMS特性的场景。
内容的提问来源于stack exchange,提问作者ngong
相关产品推荐
相关产品推荐

