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:根与子配置作用域图

根与子 build.gradle 配置作用域结构 根 build.gradle plugins(apply false) allprojects / subprojects allprojects {} repositories, common tasks subprojects {} java version, encoding, deps 子模块 A build.gradle apply plugin: 'java' 子模块 B build.gradle apply plugin: 'java' 作用域说明 实线: subprojects 只作用于子模块 虚线: allprojects 也影响根 子模块 build.gradle 接收配置后 再叠加自身插件

3.3 实现流程:从根到子配置抽取

  1. 在根 build.gradle 中使用 plugins 块声明所有插件版本,并通过 apply false 延迟应用。
  2. 通过 allprojects 配置仓库和公共任务(如 clean 扩展)。
  3. 通过 subprojects 配置 Java 编译版本、编码、公共依赖。
  4. 子模块 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 解耦。