
在 Maven 多模块项目中,若需从父 POM(packaging=pom)统一生成包含所有子模块产物(如 WAR、EAR、TAR)的 ZIP 包,必须确保子模块已完成构建再执行组装;否则因 target/ 被 clean 清空且子模块尚未输出,会导致 archive cannot be empty 错误。
在 maven 多模块项目中,若需从父 pom(packaging=pom)统一生成包含所有子模块产物(如 war、ear、tar)的 zip 包,必须确保子模块已完成构建再执行组装;否则因 `target/` 被 `clean` 清空且子模块尚未输出,会导致 `archive cannot be empty` 错误。
Maven 的标准生命周期(clean → validate → compile → package → verify → install → deploy)是按 reactor 顺序逐模块执行各阶段,而非“先全局跑完所有模块的 package,再统一跑所有模块的 verify”。因此,当父 POM 的 maven-assembly-plugin 绑定到 <phase>package</phase> 时,它会在父模块自身的 package 阶段触发——此时子模块虽已编译,但其 package 阶段输出(如 module1/target/app.war)可能尚未完成写入,或因 reactor 执行时序未严格保证父子依赖顺序而不可靠。
更关键的是:Maven 并不存在 post-package 或 after-modules 这类内置生命周期阶段。试图将插件绑定到 verify 阶段(如答案中选项2)虽能“凑效”,但属于反模式——verify 阶段语义是验证构建产物质量(如运行集成测试、检查代码覆盖率),而非生成分发包,这会破坏构建可预测性与工具链兼容性(例如 CI 系统或 IDE 可能跳过 verify)。
✅ 推荐方案:引入专用聚合模块(Aggregator Module)
创建一个独立的、不参与业务逻辑的子模块(如 assembly-module),将其置于 reactor 末尾,并通过 <dependencies></dependencies> 显式声明对 module1、module2、module3 的依赖。Maven 的 reactor 排序机制会自动确保该模块最后构建,且其 package 阶段执行时,所有依赖模块的构建产物均已就位。
示例结构:
Java Maven 项目审查工作流的通用输入处理。当 Java Maven 项目以 ZIP压缩包或 GitLab 仓库 URL 形式提供且需要...时使用。
mainapp/
├── pom.xml ← 父 POM(仅定义 modules)
├── module1/ ← 生成 WAR
├── module2/ ← 生成 TAR
├── module3/ ← 生成 EAR
└── assembly-module/ ← 新增:仅负责组装,无源码
└── pom.xmlassembly-module/pom.xml 关键配置:
<project>
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.empresa.nombre.app</groupId>
<artifactId>mainapp</artifactId>
<version>1.0.0</version>
</parent>
<artifactId>assembly-module</artifactId>
<packaging>pom</packaging>
<dependencies>
<!-- 确保 reactor 中此模块排在最后 -->
<dependency>
<groupId>com.empresa.nombre.app</groupId>
<artifactId>module1</artifactId>
<version>${project.version}</version>
<type>war</type>
</dependency>
<dependency>
<groupId>com.empresa.nombre.app</groupId>
<artifactId>module2</artifactId>
<version>${project.version}</version>
<type>tar</type>
</dependency>
<dependency>
<groupId>com.empresa.nombre.app</groupId>
<artifactId>module3</artifactId>
<version>${project.version}</version>
<type>ear</type>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<appendAssemblyId>false</appendAssemblyId>
<finalName>finalName</finalName>
<descriptors>
<descriptor>src/main/assembly/assembly.xml</descriptor>
</descriptors>
<outputDirectory>${project.build.directory}/..</outputDirectory>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>同时,在父 POM 的 <modules></modules> 中追加该模块:
<modules> <module>module1</module> <module>module2</module> <module>module3</module> <module>assembly-module</module> <!-- 新增 --> </modules>
⚠️ 注意事项:
-
assembly.xml描述符中应使用${project.parent.basedir}定位子模块输出路径(如../module1/target/*.war),避免硬编码。 - 确保子模块的
<packaging></packaging>类型与依赖中声明的<type></type>一致(如war、ear),否则依赖解析失败。 - 构建命令保持为
mvn clean package即可,无需额外参数——Maven 自动按依赖关系排序 reactor。 - 若需跳过其他模块的测试以加速组装,可对
assembly-module单独执行:mvn -pl assembly-module -am clean package(-am表示 also-make 依赖模块)。
此方案符合 Maven 设计哲学:用模块职责分离替代生命周期阶段“hack”,既保证时序可靠性,又提升可维护性与团队协作清晰度。

















