3. 配置根项目 build.gradle
多模块 Gradle 构建的根项目 build.gradle 是全局配置的起点。它将配置策略分为三个层级:根项目自身、所有项目(含根)、仅子项目。核心控制手段是 allprojects 和 subprojects 闭包,配合全局仓库与通用插件声明,实现“一处定义,到处生效”的复用目标。
关键原则:根项目的 build.gradle 只应包含跨子项目共享的配置,避免将子项目独有逻辑写入根脚本。
1. 全局仓库与通用插件
全局仓库使用根项目顶层的 repositories 块声明;若同时使用 allprojects,则建议在 allprojects 内声明,确保所有子项目也会继承。
通用插件(如 java-library、maven-publish)通常通过 plugins 块置于根脚本顶部,或放入 allprojects 中的 apply plugin。现代 Gradle 推荐使用 plugins 块 + apply false 模式统一版本管理。
// 根项目 build.gradle
plugins {
id 'java-library' apply false // 声明但不立即应用
id 'maven-publish' apply false
id 'com.github.johnrengelman.shadow' version '7.1.2' apply false
}
allprojects {
group = 'com.example'
version = '1.0.0'
repositories {
mavenCentral()
maven { url 'https://jitpack.io' }
}
}
subprojects {
apply plugin: 'java-library'
java {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
dependencies {
testImplementation 'org.junit.jupiter:junit-jupiter:5.9.2'
}
}
2. allprojects 与 subprojects 语义对比
| 维度 | allprojects | subprojects |
|---|---|---|
| 包含范围 | 根项目 + 所有子项目 | 仅子项目(不含根) |
| 典型用途 | 全局仓库、group/version、通用插件版本声明 | 构建工具链配置、通用依赖、代码检查规则 |
| 执行顺序 | 先于 subprojects 执行(在配置阶段) | 在 allprojects 之后执行 |
| 风险 | 若在 allprojects 中应用插件,根项目也会被应用(可能不需要) | 安全,不会影响根项目的类路径 |
3. 配置流程图:根脚本执行逻辑
4. 实战步骤:构建稳健的根配置
- 声明插件版本:在
plugins块中用apply false统一管理,避免子项目间版本碎片。 - 配置全局元数据:在
allprojects中设置group、version以及仓库地址。 - 定义子项目默认构建行为:在
subprojects中应用通用插件(如java-library)、统一 Java 版本、添加通用测试依赖。 - 差异化配置下放到子项目:每个子项目的
build.gradle只保留独有依赖、专属插件或特殊任务。 - 验证配置继承:运行
gradle projects和gradle dependencies检查各子项目是否正确继承了仓库和版本。
实践建议:使用 allprojects 声明仓库时,避免在其中直接 apply plugin,否则根项目也会被应用(导致冗余的 Java Library 插件)。推荐将 apply plugin 移至 subprojects。
5. 常见错误与调试
- 根项目错误地参与了编译:根项目通过
allprojects应用了java-library,导致根目录下产生了build目录,且根项目的src/main/java也被编译。解决方案:改为subprojects应用插件。 - 仓库声明在子项目内重复:若未在
allprojects声明仓库,每个子项目的build.gradle都要写一遍repositories,且易引发不一致。统一放在allprojects中一次解决。 - 依赖版本冲突:不同子项目通过
implementation引入同一库的不同版本。建议在subprojects的dependencies中使用constraints或借助java-platform/version catalog统一版本。 - 配置延迟与顺序问题:若在
allprojects中读取子项目的属性(如project.name),需注意配置阶段尚未完成。避免在allprojects闭包中执行依赖于子项目配置的任务。
// 错误示例:在 allprojects 中直接 apply plugin,导致根项目也被编译
allprojects {
apply plugin: 'java-library' // 不推荐
repositories { mavenCentral() }
}
// 正确示例:只对子项目应用插件
subprojects {
apply plugin: 'java-library'
}
性能提醒:避免在 allprojects 或 subprojects 中放置耗时的闭包(如文件扫描、网络请求)。这些闭包在每个项目配置时都会执行,线性放大配置时间。应将计算或 I/O 操作移至任务动作中。
6. 扩展:按生命周期精细化配置
除了 allprojects 和 subprojects,Gradle 还支持在 gradle.beforeSettings 和 gradle.settingsEvaluated 中注入早期配置。对于多模块项目,建议遵循以下粒度划分:
| 配置位置 | 典型内容 | 执行阶段 |
|---|---|---|
settings.gradle | 项目包含声明、全局构建缓存、插件管理 | 初始化 |
根 build.gradle 顶层 | 插件版本声明、全局属性 | 配置初期 |
allprojects {} | 仓库、group/version、公共扩展 | 配置中 |
subprojects {} | 通用插件、基础依赖、编译选项 | 配置中 |
子项目 build.gradle | 独有依赖、专属任务、第三方插件 | 配置后期 |
遵循此层级,可使大型多模块项目保持配置整洁、易于排错,并且最大程度复用代码。