使用Java 9模块解决Maven遗留代码JarHell问题遇阻
一、自动模块的传递性
自动模块默认具备传递性。当非模块化Jar被声明为自动模块后,它会将自身依赖的所有Jar(即使是非模块化的)自动推断为依赖模块,JVM会尝试解析这些传递依赖。但问题在于,部分老依赖(如com.sun.xml.bind这类)本身没有模块描述符,当它们被自动模块依赖时,JVM无法自动识别对应的模块名,就会抛出找不到模块的错误。
二、遗留代码的处理方案
1. 显式添加缺失的自动模块依赖
针对报错中提到的com.sun.xml.txw2这类模块,直接将对应的Jar作为依赖引入到API模块中。这些Jar本身是非模块化的,JVM会自动将它们转为自动模块,从而被依赖它的模块识别。比如在Maven中添加:
<dependency> <groupId>com.sun.xml.txw2</groupId> <artifactId>txw2</artifactId> <version>匹配jrs-rest-java-client的对应版本</version> </dependency>
可通过mvn dependency:tree命令查看依赖树,找到jrs-rest-java-client依赖的准确版本。
2. 用JVM参数补全依赖关系
在运行时通过JVM参数显式指定需要的模块及依赖关系:
--add-modules com.sun.xml.txw2:强制将该模块加入模块路径--add-reads com.sun.xml.bind=com.sun.xml.txw2:允许com.sun.xml.bind模块读取com.sun.xml.txw2模块的内容
如果缺失模块较多,可使用--add-modules ALL-MODULE-PATH,让JVM加载模块路径上的所有自动模块,适合快速验证场景。
3. 回归依赖排除解决JarHell
放弃模块拆分,直接在Spring Boot项目中排除冲突依赖,保留jrs-rest-java-client需要的版本。比如若Spring与客户端的jaxb相关依赖版本冲突,可在Maven中排除Spring的对应依赖:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <exclusions> <exclusion> <groupId>com.sun.xml.bind</groupId> <artifactId>jaxb-core</artifactId> </exclusion> </exclusions> </dependency>
随后显式引入jrs-rest-java-client依赖的jaxb版本,保证依赖一致性。
4. 用maven-shade-plugin打包超级Jar
将API模块与所有依赖(含jrs-rest-java-client及其依赖)打包成一个带模块描述符的超级Jar,手动指定模块名和依赖关系,避免自动模块的推断问题。该方式配置稍复杂,适合需严格模块化的场景。
三、是否需要显式声明整个依赖栈?
不需要完整声明整个依赖栈,但需要显式声明JVM无法自动识别的依赖。自动模块会传递依赖,但对于无明确模块名的老Jar,JVM可能无法正确推断模块名,导致找不到模块。此时只需添加报错中提到的缺失模块对应的依赖即可,其他能被自动推断的依赖无需额外声明。
内容的提问来源于stack exchange,提问作者Cerber

