配置根项目 build.gradle:全局仓库、通用插件、allprojects 与 subprojects 块

多模块 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 语义对比

维度allprojectssubprojects
包含范围根项目 + 所有子项目仅子项目(不含根)
典型用途全局仓库、group/version、通用插件版本声明构建工具链配置、通用依赖、代码检查规则
执行顺序先于 subprojects 执行(在配置阶段)在 allprojects 之后执行
风险若在 allprojects 中应用插件,根项目也会被应用(可能不需要)安全,不会影响根项目的类路径

3. 配置流程图:根脚本执行逻辑

根项目 build.gradle 配置层级 根项目 build.gradle allprojects { ... } subprojects { ... } 全局仓库 / group:version 应用 java-library / 通用测试依赖 子项目 A 子项目 B 子项目 C 虚线表示 allprojects / subprojects 中配置自动注入到子项目 配置阶段执行顺序:插件声明 → allprojects → subprojects → 各子项目自身 build.gradle

4. 实战步骤:构建稳健的根配置

  1. 声明插件版本:在 plugins 块中用 apply false 统一管理,避免子项目间版本碎片。
  2. 配置全局元数据:在 allprojects 中设置 group、version 以及仓库地址。
  3. 定义子项目默认构建行为:在 subprojects 中应用通用插件(如 java-library)、统一 Java 版本、添加通用测试依赖。
  4. 差异化配置下放到子项目:每个子项目的 build.gradle 只保留独有依赖、专属插件或特殊任务。
  5. 验证配置继承:运行 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独有依赖、专属任务、第三方插件配置后期

遵循此层级,可使大型多模块项目保持配置整洁、易于排错,并且最大程度复用代码。