3. 根 build.gradle 与子 build.gradle 分工:公共配置抽取、allprojects/subprojects 区别、plugins 块使用
3.1 原理:配置的层级与作用域
在多模块 Gradle 项目中,根 build.gradle 作为项目树的顶级配置文件,负责全局统一设置;子 build.gradle 则专注于模块本身特有的配置。它们之间通过 allprojects、subprojects 和 plugins 块实现职责分离。
| 配置层级 | 作用范围 | 典型用途 |
|---|---|---|
allprojects {} | 根项目 + 所有子模块 | 仓库、通用依赖管理、共有的任务扩展 |
subprojects {} | 仅子模块(不含根) | Java 版本、默认编码、测试框架 |
plugins {}(根) | 全局插件版本声明 | 在 buildscript 中管理插件版本,子模块通过 apply false 避免重复 |
plugins {}(子) | 本模块应用插件 | 仅启动需要插件的逻辑 |
关键区别:allprojects 会牵连根项目自身,通常不推荐在根项目中添加 Java、Spring Boot 等应用插件;subprojects 则只影响子模块,更安全。而 plugins 块通过 apply false 实现“声明 + 延迟应用”,避免多模块中插件版本冲突。
核心原则:根 build.gradle 只做基础设施(仓库、插件版本、通用属性),子 build.gradle 只做模块业务(应用插件、模块依赖、专属配置)。
3.2 内联 SVG:根与子配置作用域图
3.3 实现流程:从根到子配置抽取
- 在根 build.gradle 中使用 plugins 块声明所有插件版本,并通过
apply false延迟应用。 - 通过
allprojects配置仓库和公共任务(如clean扩展)。 - 通过
subprojects配置 Java 编译版本、编码、公共依赖。 - 子模块 build.gradle 中仅使用
plugins应用需要的插件,并在dependencies块中声明模块私有依赖。
配置示例:根 build.gradle
plugins {
id 'java' apply false
id 'org.springframework.boot' version '3.2.0' apply false
id 'io.spring.dependency-management' version '1.1.4' apply false
}
allprojects {
repositories {
mavenCentral()
mavenLocal()
}
}
subprojects {
apply plugin: 'java' // 或在子模块plugins块中应用
group = 'com.example'
version = '1.0.0'
java {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
tasks.withType(JavaCompile).configureEach {
options.encoding = 'UTF-8'
}
}
配置示例:子模块 build.gradle(module-a)
plugins {
id 'org.springframework.boot'
id 'io.spring.dependency-management'
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
3.4 调试与验证
- 查看配置继承结果:执行
gradle projects观察项目树,或gradle properties查看每个项目的属性。 - 检查插件是否被正确应用:
gradle buildEnvironment列出各模块的插件依赖。 - 验证仓库配置:
gradle dependencies --configuration compileClasspath看仓库顺序。
调试命令:
gradle projects 输出各模块路径;gradle properties -p module-a 单独查看子模块属性。
3.5 常见错误与避免
| 错误场景 | 原因 | 正确做法 |
|---|---|---|
在 allprojects 中应用 Spring Boot 插件 | 导致根项目也尝试生成 bootJar | 放到 subprojects 或子模块单独应用 |
在子模块中重复 apply plugin: 'java' | 已在 subprojects 中应用,引发版本冲突 | 只在一处声明,或使用 plugins 块管理 |
plugins 块放在 allprojects 内部 | plugins 块只能出现在顶级,语法错误 | 仅放在各 build.gradle 顶层 |
| 在子模块中重新声明仓库 | 与 allprojects 中的仓库重复 | 移除子模块的仓库配置 |
特别提醒:
allprojects 和 subprojects 中的配置会作用于所有子模块,若某个模块需要特殊仓库或 JDK 版本,不要在此处覆盖,而应在该模块的 build.gradle 中先 afterEvaluate 调整或使用条件判断。
3.6 性能与稳定性优化
- 使用
plugins块管理版本:避免在buildscript中声明版本导致项目加载变慢。 - 限定
subprojects范围:如果某些子模块不需要 Java 编译,用project(':module-name') {}单独配置,避免全局配置开销。 - 缓存公共依赖:在
allprojects中统一配置resolutionStrategy的缓存策略,减少远程仓库查询。 - 减少不必要的
allprojects任务:只在根上添加全局任务(如 sonar、lint),避免子模块重复执行。
3.7 部署场景配置
发布时将公共版本直接写入根 build.gradle 的 plugins 块,子模块无需更改版本。若使用 CI/CD 可添加如下配置片段提取公共属性:
// 根 build.gradle 统一配置版本号
ext {
springBootVersion = '3.2.0'
guavaVersion = '33.0.0-jre'
}
subprojects {
dependencies {
if (project.name != 'core') {
implementation "com.google.guava:guava:${guavaVersion}"
}
}
}
这样当升级版本时只需修改根一处,所有子模块自动生效。
推荐实践:将公共版本号统一提取到
gradle.properties 或 version.gradle 文件中,再通过 apply from 加载,与 build.gradle 解耦。