1054 字
约 3 分钟
8
S06-B01 · Maven 的三层模型与多模块构建

适用读者:会 mvn package 但说不清"多模块怎么排、依赖从哪来"的人。本系列第一篇。
前置:S01-B03(Maven 安装与镜像)、S01-J07(依赖治理)。
实测环境:Maven 3.8.7 / JDK 17(2026-11-05)。
覆盖旧文:A-1855(Maven 捋清楚,242 点)。
覆盖扩展:E-S06-001(三层模型)、E-S06-002(skipTests 两种开关)。
下一篇:S06-B02 · Lombok。


1. 一句话结论

Maven 只有三个概念:坐标(我是谁)、生命周期(怎么造)、仓库(零件从哪来)。多模块只是"把一个坐标拆成多个,用 parent 串起来"。

层 内容 出问题时的表现
坐标 groupId:artifactId:version 依赖找不到(坐标错/版本不存在)
生命周期 validate→compile→test→package→verify→install→deploy 跑错阶段(以为只编译,其实跑了测试)
仓库 本地 → 镜像/私服 → 中央 拉不到(网络/镜像/权限)

与 S01 的分工:S01-B03 讲"装与镜像"、S01-J07 讲"依赖冲突",本篇只讲工程结构。


2. 实测:三模块工程的构建顺序

ms-parent (pom)
├── core (jar)
└── app  (jar,依赖 core)
$ mvn -B -pl app -am validate

实测输出:

[INFO] Reactor Build Order:
[INFO] ms-parent    [pom]
[INFO] core         [jar]
[INFO] app          [jar]
参数 作用
-pl app 只构建 app 模块
-am(also make) 同时构建它依赖的模块
-amd 构建依赖它的模块(下游)
-rf :core 从 core 继续(失败续跑)

"reactor"就是 Maven 自己算出来的构建顺序——它按依赖关系拓扑排序,parent 永远最前。


3. 三种"版本放哪"的方式

方式 写法 适用
parent 继承 <parent> + 子模块省略版本 单一项目族
dependencyManagement(BOM) 只声明版本,不引入依赖 多项目共享版本
import 外部 BOM <scope>import</scope> 用 Spring Boot 等官方 BOM

判据:"这个版本是"我们项目的",还是"全公司/全生态的"?" 后者 → BOM。


4. 实测:-DskipTests 与 -Dmaven.test.skip=true 的区别(E-S06-002)

场景:core 里有一个用了 JUnit 的测试类,但没有引入 JUnit 依赖。

$ mvn -pl app -am package -DskipTests
[ERROR] COMPILATION ERROR :
[ERROR] CalcTest.java:[2,29] package org.junit.jupiter.api does not exist

失败。因为 -DskipTests 只跳过"运行测试",仍然编译测试源码。

$ mvn -pl app -am package -Dmaven.test.skip=true
# BUILD SUCCESS → app/target/app-1.0.0.jar, core/target/core-1.0.0.jar
开关 编译测试 运行测试 适用
-DskipTests ✅ 仍编译 ❌ 跳过 测试代码可编译、只是不想跑
-Dmaven.test.skip=true ❌ 不编译 ❌ 跳过 缺测试依赖、快速打包
-Dtest=Xxx ✅ 只跑指定测试 定位单个失败

这条差异解释了大量"本地能打包、CI 挂了"的困惑:CI 上用了 -DskipTests,而测试依赖没配齐。


5. 一个最小可跑的多模块工程(实测)

$ java -cp app/target/classes:core/target/classes demo.Main
1+2=3

注意:手工 -cp 只是演示;生产用 maven-jar-plugin + manifest 或 spring-boot-maven-plugin 打可执行 jar。


6. 五个误区

误区 真相
"-DskipTests 不编译测试" 仍编译(E-S06-002 实测)
"mvn package 只打包" 会跑 compile+test
"子模块必须写 version" 有 parent/BOM 时可省
"-pl 会带上依赖模块" 需 -am
"多模块=微服务" 只是构建单元,与部署无关

7. 自检

  1. Maven 三层模型分别对应什么故障现象?
  2. -pl 与 -am 的区别?
  3. reactor 顺序由什么决定?
  4. -DskipTests 与 -Dmaven.test.skip=true 的差别(用实测解释)?
  5. 什么时候该用 BOM 而不是 parent?

8. 下一篇

S06-B02 · Lombok:注解矩阵、原理与陷阱

构建讲完,下一篇讲"编译期变出代码"的机制:Lombok 的 16 个注解、它为什么需要 IDE 插件,以及三个常见陷阱。


本篇属于系列《S06 · Java 工程化与组件》。旧文来源:A-1855;扩展点 E-S06-001/002。多模块与两种 skip 开关为 2026-11-05 实测(Maven 3.8.7 / JDK 17)。

S06-B01 · Maven 的三层模型与多模块构建
https://www.clxhxhhr.top/posts/5255/
作者
clxstart
发布于
2024-12-31
许可协议
CC BY-NC-SA 4.0
评论
0 条
还没有评论,先写一条吧。