Maven与Java 9环境下使用含拆分包的第三方构件问题
嘿,这个问题我之前帮好多做Java 9适配的开发者踩过坑!Java 9的模块系统对**拆分包(split packages)**的严格校验确实会给遗留项目添堵,不过针对你这种两个JAR包的同一包下没有重叠类的情况,有几个非常实用的解决办法:
方案1:合并两个遗留JAR包
既然两个JAR里的P包没有重复类,最省心的办法就是把它们合并成一个JAR,这样模块系统只会看到一个P包的来源。用Maven的shade插件就能轻松搞定,配置示例如下:
<build> <plugins> <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> <!-- 不需要生成简化的pom就设为false --> <createDependencyReducedPom>false</createDependencyReducedPom> <artifactSet> <includes> <!-- 替换成你的两个第三方构件的groupId:artifactId --> <include>com.your.deps:A</include> <include>com.your.deps:B</include> </includes> </artifactSet> <transformers> <!-- 如果不需要指定主类可以删掉这个transformer --> <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> <mainClass>com.myapp.MainClass</mainClass> </transformer> </transformers> </configuration> </execution> </executions> </plugin> </plugins> </build>
执行mvn package后,生成的shaded JAR就包含了A和B的所有内容,模块系统自然不会再报拆分包错误。
方案2:使用--patch-module参数绕过校验
如果不想合并JAR(比如依赖更新频繁,合并太麻烦),可以用Java 9提供的--patch-module参数,把其中一个JAR的P包"补丁"到另一个JAR对应的自动模块里。这样模块系统会认为P包只来自被补丁的模块。
在Maven编译阶段配置
修改maven-compiler-plugin的配置,添加编译参数:
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.11.0</version> <configuration> <release>9</release> <compilerArgs> <arg>--patch-module</arg> <!-- 这里的A是A.jar的自动模块名称,B.jar是要补丁的包来源 --> <arg>A=${project.basedir}/target/dependency/B.jar</arg> </compilerArgs> </configuration> </plugin>
在测试/运行阶段配置
还要给maven-surefire-plugin加上相同的参数,保证测试和运行时也生效:
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>3.1.2</version> <configuration> <argLine>--patch-module A=${project.basedir}/target/dependency/B.jar</argLine> </configuration> </plugin>
小提示:自动模块的名称可以通过
jar --describe-module --file A.jar命令查看,一般是JAR文件名去掉版本号(比如A-2.0.jar的自动模块名是A)。
方案3:将其中一个JAR转为显式模块(可选,较复杂)
如果有能力重新打包第三方构件,可以给其中一个JAR添加module-info.java,指定它导出P包,另一个JAR保持自动模块状态。不过这个方案需要修改第三方依赖,对于纯遗留构件来说不太推荐,除非你能控制依赖的发布。
选哪个方案?
- 如果你希望一劳永逸,不用额外配置参数,优先选方案1合并JAR;
- 如果依赖更新频繁,合并成本高,或者需要保留原有依赖结构,选**方案2用
--patch-module**更灵活。
内容的提问来源于stack exchange,提问作者taranion
相关产品推荐
相关产品推荐

