You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 10:10:31