1. 单体项目与多模块项目的差异
从单体走向多模块是 Gradle 项目规模增长中的关键转折点。本章从项目结构、构建速度和代码复用三个维度拆解两者的本质差异,为后续多模块配置与优化建立基础认知。
1.1 项目结构对比
单体项目将所有源码、资源、配置放在同一模块内;多模块项目将功能拆分为独立子模块,每个模块有明确的职责边界。
| 对比维度 | 单体项目 | 多模块项目 |
|---|---|---|
| 目录组织 | 单一 src/ 下按 package 划分 | 每个模块独立 src/ ,根项目仅含配置 |
| 构建文件 | 单个 build.gradle | 根 build.gradle + 每个模块 build.gradle |
| 模块间依赖 | 同一 JVM 类路径下直接引用 | 通过 project() 声明依赖,Gradle 管理编译顺序 |
| 资源隔离 | 无,易冲突 | 模块内独立,资源路径不重合 |
| 部署单元 | 单一 JAR/WAR | 可独立产出 JAR,按需组合部署 |
单体项目典型配置:
// build.gradle(单体)
plugins {
id 'java'
id 'application'
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web:2.7.0'
}
多模块项目典型配置:
// settings.gradle(根项目)
rootProject.name = 'my-app'
include 'common', 'api', 'service', 'web'
// web/build.gradle
dependencies {
implementation project(':common')
implementation project(':api')
implementation project(':service')
}
1.2 构建速度影响
单体项目每次修改都必须重新编译整个工程。多模块项目借助 Gradle 的增量编译与任务缓存,仅重新构建受影响模块及其依赖链。
- 本地增量编译:Gradle 通过输入/输出快照判断哪些任务需要重跑,多模块粒度更细,跳过无变化模块。
- 构建缓存:各模块可单独缓存,CI 中命中缓存时直接复用产物,节省 60%~90% 构建时间。
- 并发构建:Gradle 并行执行无依赖的模块任务,充分利用多核 CPU。
实测参考:某电商项目从单体迁移为 6 个模块后,全量构建时间从 8 分钟降至 2 分钟;增量修改后仅需 30 秒(原单体仍需 8 分钟)。
1.3 代码复用路径
多模块项目通过 Gradle 的 api 与 implementation 配置控制依赖暴露范围,实现精确的复用与封装。
| 配置 | 暴露给下游 | 典型场景 |
|---|---|---|
api | 所有间接依赖方 | 公共工具类、接口定义层 |
implementation | 仅当前模块(不泄漏) | 内部实现细节、数据库驱动 |
compileOnly | 仅编译期,不参与打包 | Lombok、注解处理器 |
// :common/build.gradle
dependencies {
api 'com.google.guava:guava:31.1-jre'
}
// :api/build.gradle
dependencies {
implementation project(':common') // 使用 common 中的 Guava,但不会传递给 :web
}
依赖传播原则:implementation 依赖的 api 依赖会透传,避免重复 jar 冲突;compileClasspath 与 runtimeClasspath 分离,提供更快的配置解析。
本章核心结论
- 结构:多模块以模块为边界,根项目仅做组合;单体以包为边界,所有代码平铺。
- 速度:多模块利用增量、缓存、并行构建,全量构建提速 3~5 倍,增量构建提速 10~20 倍。
- 复用:通过
api/implementation精确控制依赖可见性,避免 jar 冲突与无用依赖。