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

使用Maven Assembly聚合子模块时如何跳过子模块构建

解决方案与问题解答

使用的配置

  • Maven:3.6.3
  • Maven Assembly:3.3.0

核心矛盾解决:既聚合子模块内容又避免重复构建

你遇到的问题本质是:父pom作为聚合模块,要么显式声明子模块触发构建,要么无法访问子模块的构建产物/源码。这里提供两种可行方案:

方案1:通过moduleSets配置+全局跳过子模块构建(仅在目标Profile生效)

在父pom的Profile里,配置Assembly插件的moduleSets包含所有子模块,同时添加全局属性跳过子模块的编译、测试等构建步骤,无需修改任何子模块pom:

<profile>
  <id>assemble-all</id>
  <properties>
    <!-- 全局跳过子模块的编译、测试、打包流程 -->
    <maven.compiler.skip>true</maven.compiler.skip>
    <maven.test.skip>true</maven.test.skip>
    <maven.jar.skip>true</maven.jar.skip>
  </properties>
  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-assembly-plugin</artifactId>
        <version>3.3.0</version>
        <executions>
          <execution>
            <id>assemble-all</id>
            <phase>package</phase>
            <goals>
              <goal>single</goal>
            </goals>
            <configuration>
              <descriptors>
                <descriptor>${project.basedir}/src/main/assembly/module-assembly.xml</descriptor>
              </descriptors>
            </configuration>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>
</profile>

对应的通用描述符module-assembly.xml(无需为每个父模块修改):

<assembly xmlns="http://maven.apache.org/ASSEMBLY/2.1.0"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.1.0 http://maven.apache.org/xsd/assembly-2.1.0.xsd">
  <id>all-modules</id>
  <formats>
    <format>jar</format>
  </formats>
  <includeBaseDirectory>false</includeBaseDirectory>
  <moduleSets>
    <moduleSet>
      <!-- 自动包含父模块下的所有子模块 -->
      <includeSubModules>true</includeSubModules>
      <sources>
        <includeModuleDirectory>true</includeModuleDirectory>
        <!-- 打包子模块的源码和资源 -->
        <fileSets>
          <fileSet>
            <directory>${module.basedir}/src/main/java</directory>
            <outputDirectory>/</outputDirectory>
          </fileSet>
          <fileSet>
            <directory>${module.basedir}/src/main/resources</directory>
            <outputDirectory>/</outputDirectory>
          </fileSet>
        </fileSets>
      </sources>
    </moduleSet>
  </moduleSets>
</assembly>

注意:第一次执行或修改子模块代码后,需先执行mvn clean install构建子模块,之后再激活Profile执行聚合:mvn clean package -P assemble-all,这样既不会重复构建子模块,又能获取最新的源码/资源。

方案2:通过dependencySet解压子模块Jar打包(适合已构建好的子模块)

如果不想直接操作源码,而是用子模块的构建产物Jar,可在父pom中依赖所有子模块,再通过Assembly的dependencySet解压合并:

父pom的Profile配置:

<profile>
  <id>assemble-all-jars</id>
  <dependencies>
    <!-- 添加所有子模块依赖 -->
    <dependency>
      <groupId>${project.groupId}</groupId>
      <artifactId>service-api</artifactId>
      <version>${project.version}</version>
    </dependency>
    <dependency>
      <groupId>${project.groupId}</groupId>
      <artifactId>service-impl</artifactId>
      <version>${project.version}</version>
    </dependency>
    <dependency>
      <groupId>${project.groupId}</groupId>
      <artifactId>core</artifactId>
      <version>${project.version}</version>
    </dependency>
    <dependency>
      <groupId>${project.groupId}</groupId>
      <artifactId>facade</artifactId>
      <version>${project.version}</version>
    </dependency>
  </dependencies>
  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-assembly-plugin</artifactId>
        <version>3.3.0</version>
        <executions>
          <execution>
            <id>assemble-all-jars</id>
            <phase>package</phase>
            <goals>
              <goal>single</goal>
            </goals>
            <configuration>
              <descriptors>
                <descriptor>${project.basedir}/src/main/assembly/jar-assembly.xml</descriptor>
              </descriptors>
            </configuration>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>
</profile>

通用描述符jar-assembly.xml:

<assembly xmlns="http://maven.apache.org/ASSEMBLY/2.1.0"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.1.0 http://maven.apache.org/xsd/assembly-2.1.0.xsd">
  <id>all-jars</id>
  <formats>
    <format>jar</format>
  </formats>
  <includeBaseDirectory>false</includeBaseDirectory>
  <dependencySets>
    <dependencySet>
      <!-- 仅包含当前父模块的子模块依赖 -->
      <includes>
        <include>${project.groupId}:service-api</include>
        <include>${project.groupId}:service-impl</include>
        <include>${project.groupId}:core</include>
        <include>${project.groupId}:facade</include>
      </includes>
      <!-- 解压所有子模块Jar到根目录 -->
      <unpack>true</unpack>
      <!-- 排除传递依赖,解决你之前Shade插件的问题 -->
      <useTransitiveDependencies>false</useTransitiveDependencies>
    </dependencySet>
  </dependencySets>
</assembly>

这种方式需要子模块已经构建并安装到本地仓库,执行命令同样是mvn clean package -P assemble-all-jars,无需额外参数。

针对你的疑问逐一解答

  1. 遗漏的配置/属性:方案1中使用的maven.compiler.skip等全局跳过属性,以及Assembly的includeSubModules配置,是你之前没用到的关键;方案2的useTransitiveDependencies可直接解决传递依赖过滤问题。
  2. 通用命令:上述两种方案都只需激活对应Profile,无需-pl或其他模块指定参数,命令统一简洁。
  3. 单次设置跳过子模块构建:方案1通过在父pom的Profile中定义全局跳过属性,无需修改任何子模块pom,完全满足需求。
  4. 使用fileSets的可行性:完全可以。如果子模块结构完全一致,通用描述符里可以用fileSets直接指定子模块的源码/资源目录,比如:
    <fileSets>
      <fileSet>
        <directory>${project.basedir}/service-api/src/main/java</directory>
        <outputDirectory>/</outputDirectory>
      </fileSet>
      <fileSet>
        <directory>${project.basedir}/service-impl/src/main/resources</directory>
        <outputDirectory>/</outputDirectory>
      </fileSet>
      <!-- 其他子模块路径依次添加 -->
    </fileSets>
    
    缺点是需要在描述符里枚举所有子模块路径,但胜在无需依赖子模块构建状态,直接读取源码。
  5. 解压子模块Jar重新打包:方案2就是这种实现,唯一需要注意的是修改代码后必须先执行mvn clean install构建子模块,确保父pom能获取到最新的Jar包。

额外建议

如果Shade插件的传递依赖过滤问题是核心痛点,可以尝试在Shade插件中配置filters精准排除不需要的依赖,比如:

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-shade-plugin</artifactId>
  <version>3.2.4</version>
  <executions>
    <execution>
      <phase>package</phase>
      <goals>
        <goal>shade</goal>
      </goals>
      <configuration>
        <filters>
          <filter>
            <artifact>*:*</artifact>
            <excludes>
              <exclude>META-INF/*.SF</exclude>
              <exclude>META-INF/*.DSA</exclude>
              <exclude>META-INF/*.RSA</exclude>
              <!-- 排除特定传递依赖 -->
              <exclude>com.example:unwanted-dependency</exclude>
            </excludes>
          </filter>
        </filters>
      </configuration>
    </execution>
  </executions>
</plugin>

Shade插件本身就是为合并Jar设计的,比Assembly更适合处理依赖冲突和过滤,你可以再尝试调整。

内容的提问来源于stack exchange,提问作者Florent JITIAUX

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.11 21:14:49