问题
Maven(和 Java 生态里很多构建系统)的多模块编译开销主要来自:
✅ 依赖模块构建的串行性
✅ 每次 JVM 冷启动
✅ 插件和 POM 的解析解析 → IO、网络
✅ 对改动粒度的感知不足(太粗)
1. 最基础也最重要的优化:避免全量 clean
很多人有个坏习惯:
mvn clean install
-
每次 clean 都会删掉 target,下次会全量编译
正确做法(开发循环):
mvn install
mvn compile
Maven 的编译是基于「时间戳」增量的 → 没改的模块会直接跳过。
2. 用 mvnd / Maven Daemon
Maven 传统缺点是:
-
每次 CLI 启动都要 JVM 热起来
-
解析 POM、下载依赖、加载插件 → 重复 IO
-
串行构建模块
Apache 的官方解决方案是:mvnd
它的优势是:
✅ 守护进程 → JVM 常驻
✅ 并行模块编译
✅ POM/插件/依赖树解析缓存
✅ 任务调度更智能
示例:
mvnd -T 4 compile
会并行编译可并行的模块。
👉 在大型多模块项目里往往能 2-10 倍提速。
3. 利用并行构建
Maven 3.0+ 自带并行构建支持:
mvn -T 4 compile
-
-T 4表示用 4 线程 -
-T 1C表示按 CPU 核心数
缺点是:
-
需要模块间依赖树能并行
-
如果很多模块有线性依赖,效果有限
但只要有一定并行度 → 都能省时间。
⚠️ Maven 传统 CLI 的并行效果没有 mvnd 的好,因为启动开销还是存在。
4. 避免无用的模块编译
在多模块仓库里,经常是改了一个模块,却全仓库编译。
✅ 精确指定模块
mvn -am -pl my-module compile
-am = also-make (指定只编译某个模块( -pl 指定)的同时自动编译它依赖的模块)
可以避免无谓的模块编译。
5. 利用构建缓存
Maven 社区里虽然没有像 Gradle 官方的 Build Cache 那么强的分布式缓存,但也有方案:
-
Takari Lifecycle / Takari Local Cache
-
本地构建缓存
-
避免重复编译、测试
-
-
企业 CI/CD 也可以用 Artifactory / Nexus 做构建产物缓存
适合 SRE / 云原生流水线 里加速。
6. 模块拆分策略(架构层面优化)
✅ 模块粒度要适中
-
太细:依赖图复杂、编译串行
-
太粗:变更影响大
✅ 公共模块尽量稳定
-
公共接口频繁改 → 所有下游模块都要重新编译
-
用接口隔离 → SPI、API module
✅ 分阶段构建
-
拆成多个 reactor build
-
先构建公共层 → 缓存产物
7. 利用 IDE 的增量编译
开发过程中,IDE(IntelliJ、Eclipse)往往有自己内建的非常细粒度增量编译:
-
IDEA 会检测 Java 源文件变化
-
只重新编译需要的类
-
编译速度远快于 Maven CLI
很多大型公司开发流程是:
✅ 本地用 IDE 热编译/单元测试
✅ 真正要集成 → 用 Maven 命令(CI 干净构建)
8. 选择 Gradle 或 Bazel 等现代构建工具
如果你的团队能接受更大的改动:
✅ Gradle 的增量编译
-
任务输入/输出追踪
-
只重跑受影响任务
-
Build Cache → 本地、远程
✅ Bazel
-
沙盒执行
-
细粒度依赖图
-
适合超大规模 Monorepo
Maven 本身没法完全做到同等级别的增量编译。
9. 云原生构建流水线优化
如果你是做 SRE / DevOps,可以:
✅ 使用构建缓存层
-
GitHub Actions Cache
-
GitLab Cache
-
Jenkins Pipeline 缓存
✅ 用分布式缓存
-
Gradle Remote Cache
-
Bazel Remote Cache
✅ 分阶段流水线
-
拆分公共库、服务模块
-
并行流水线
总结
🎯 本地开发循环:
✅ 不要随便 clean
✅ 用 mvnd 守护进程
✅ 用并行构建(-T)
✅ 用 -pl -am 只编需要的模块
🎯 CI/CD 流程:
✅ 拆分阶段构建
✅ 启用并行构建
✅ 构建产物缓存
✅ 最终仍可做一次 clean verify 保证干净性
1085

被折叠的 条评论
为什么被折叠?



