5. Project与Settings:Project API详解、Settings文件配置、多项目构建结构、跨项目配置

这一章,我们来聊聊 Gradle 构建的骨架——Project 和 Settings。

说实话,很多初学者把 Gradle 当成一个高级版的 Maven,写写 dependencies 就完事了。但真正到了多模块项目、微服务架构、或者需要定制构建逻辑的时候,你会发现,不懂 Project 和 Settings,寸步难行。

我个人习惯把 Gradle 的构建过程想象成一场舞台剧:Settings 是导演,决定哪些演员(子项目)上场;Project 是演员,每个演员都有自己的剧本(build.gradle)。

核心要点:Project 是 Gradle 构建的基本单元,Settings 是管理这些单元的组织者。两者配合,才能构建出灵活、可维护的多项目系统。

5.1 Project API 详解

每个 build.gradle 文件,本质上就是一个 Project 对象的配置脚本。Gradle 在解析脚本时,会创建一个 Project 实例,然后把脚本里的代码委托给这个实例执行。

嗯,这里要注意:你写的 dependenciesrepositoriestask,其实都是在调用 Project 对象的方法。

5.1.1 Project 的核心属性

Project 对象暴露了很多属性,我挑几个最常用的说说:

属性名 类型 说明
name String 项目名称,默认是目录名
path String 项目的绝对路径,如 :app
description String 项目描述,可以自己设置
version Object 项目版本号,常用于发布
group Object 项目组,类似 Maven 的 groupId
projectDir File 项目所在的目录
buildDir File 构建输出目录,默认是 build/

举个例子,你可以在 build.gradle 里直接访问这些属性:

// 设置项目信息
description = "这是我的核心业务模块"
version = "2.1.0"
group = "com.example.business"

// 打印一下,方便调试
println "项目名称: ${name}"
println "构建目录: ${buildDir.absolutePath}"

我在项目中遇到过一个问题:有同事直接在 build.gradle 里硬编码了版本号,结果每个模块都要改一遍。后来我建议用 version 属性统一管理,配合 Settings 里的跨项目配置,一次改完所有模块。

5.1.2 Project 的核心方法

Project 提供了几十个方法,但日常开发中,你真正需要记住的其实不多:

  • apply():应用插件,比如 apply plugin: 'java'
  • dependencies():声明依赖
  • repositories():配置仓库
  • task():创建任务
  • subprojects():对所有子项目统一配置
  • allprojects():对当前项目及所有子项目统一配置

你想想看,subprojectsallprojects 这两个方法,是多项目构建的利器。比如你想让所有子项目都使用同一个仓库:

subprojects {
    repositories {
        mavenCentral()
    }
}

这样写,每个子项目的 build.gradle 里就不用重复写 repositories 了。干净利落。

小技巧:如果你想让根项目也应用某个配置,用 allprojects;如果只想让子项目应用,用 subprojects。根项目通常只做统筹,不参与业务构建。

5.2 Settings 文件配置

Settings 文件(settings.gradle)是 Gradle 构建的入口。Gradle 启动时,第一件事就是解析 settings.gradle,确定哪些项目参与构建。

说白了,没有 Settings 文件,Gradle 连该构建哪个项目都不知道。

5.2.1 基本配置

最简单的 settings.gradle 可能只有一行:

rootProject.name = 'my-application'

这行代码设置了根项目的名称。如果不设置,Gradle 会默认使用目录名。我个人习惯显式设置,避免因为目录改名导致构建混乱。

5.2.2 包含子项目

多项目构建的核心,就是 include 方法:

rootProject.name = 'my-application'

include 'core'
include 'web'
include 'api'
include 'common'

Gradle 会默认在根目录下寻找 core/web/ 等子目录,并把它们作为子项目。你也可以指定路径:

include ':core'
include ':web'
include ':api:rest'  // 嵌套子项目

这里有个坑,我曾经踩过:如果你把子项目放在 modules/ 目录下,需要这样写:

include 'modules:core'
include 'modules:web'

Gradle 会自动把 modules/core 映射为项目路径 :modules:core

5.2.3 动态包含项目

如果你的项目特别多,手动一个个 include 太累了。Gradle 支持动态包含:

rootProject.name = 'my-application'

// 自动包含 modules 目录下的所有子目录
file('modules').eachDir { dir ->
    include dir.name
    project(":${dir.name}").projectDir = dir
}

这样,只要在 modules/ 下新建一个目录,Gradle 就会自动把它纳入构建。我在微服务项目里经常用这个技巧,省去了每次新增服务都要改 settings.gradle 的麻烦。

注意:动态包含虽然方便,但如果你对项目顺序有要求(比如某些项目必须先构建),还是建议手动 include,并控制顺序。

5.3 多项目构建结构

多项目构建,说白了就是把一个大项目拆成多个小项目,每个小项目独立编译、测试、打包,但又能互相依赖。

我见过很多团队把多项目结构搞得乱七八糟,根目录下放了一堆业务代码,子项目之间循环依赖。嗯,这里我给出一个比较推荐的结构:

my-application/
├── settings.gradle
├── build.gradle          // 根项目,只做统筹
├── gradle.properties
├── common/               // 公共工具模块
│   └── build.gradle
├── core/                 // 核心业务模块
│   └── build.gradle
├── web/                  // Web 层模块
│   └── build.gradle
└── api/                  // API 接口模块
    └── build.gradle

每个子项目都有自己的 build.gradle,但公共配置(比如 Java 版本、仓库、插件)可以放在根项目的 build.gradle 里统一管理。

5.3.1 统一配置子项目

在根项目的 build.gradle 里,你可以这样写:

subprojects {
    apply plugin: 'java'

    group = 'com.example'
    version = '1.0.0'

    repositories {
        mavenCentral()
    }

    dependencies {
        testImplementation 'org.junit.jupiter:junit-jupiter:5.9.0'
    }

    tasks.withType(JavaCompile) {
        options.encoding = 'UTF-8'
        options.release = 17
    }
}

这样,所有子项目都自动获得了 Java 插件、统一版本号、仓库和测试依赖。每个子项目的 build.gradle 只需要写自己特有的依赖即可。

举个例子,core/build.gradle 可能只需要这样:

dependencies {
    implementation project(':common')  // 依赖 common 模块
    implementation 'org.springframework:spring-core:6.0.0'
}

是不是清爽多了?

5.4 跨项目配置

跨项目配置,指的是在一个项目中配置另一个项目的行为。Gradle 提供了几种方式:

5.4.1 使用 project() 方法

在根项目的 build.gradle 里,你可以直接操作子项目:

project(':core') {
    // 给 core 项目单独配置
    dependencies {
        implementation 'com.google.guava:guava:32.0.0-jre'
    }
}

project(':web') {
    // 给 web 项目单独配置
    apply plugin: 'war'
}

这种方式适合在根项目里集中管理特殊配置。不过我个人不太推荐滥用,因为一旦项目多了,根项目的 build.gradle 会变得臃肿不堪。

5.4.2 使用 configure() 方法

如果你需要对一组项目做相同配置,configureproject 更合适:

configure([project(':core'), project(':common')]) {
    // 这两个项目都使用 Spring
    dependencies {
        implementation 'org.springframework:spring-context:6.0.0'
    }
}

这样写,代码更简洁,意图也更明确。

5.4.3 跨项目依赖

这是多项目构建的核心功能。一个子项目可以依赖另一个子项目:

// web/build.gradle
dependencies {
    implementation project(':core')
    implementation project(':common')
}

Gradle 会自动处理构建顺序:先构建 corecommon,再构建 web。你不需要手动指定顺序,Gradle 会通过依赖图自动推导。

重要:跨项目依赖使用的是 project() 方法,而不是字符串路径。Gradle 会把它当作项目依赖,而不是外部依赖。这意味着,当你修改了 core 的代码,Gradle 只会重新编译 core 和依赖它的 web,不会全量编译。

5.4.4 在 Settings 中配置项目

Settings 文件里也可以配置项目,但通常只做路径映射:

rootProject.name = 'my-application'

include 'core'
include 'web'

// 修改子项目的名称
project(':core').name = 'business-core'
project(':web').name = 'web-application'

我曾经在一个遗留系统里遇到过项目名称和目录名不一致的情况,就是用 project().name 来修正的。不过,我建议尽量保持名称一致,否则容易把人搞晕。

5.5 知识体系总览

为了让你更直观地理解本章的知识结构,我画了一张图:

Gradle 构建核心:Project 与 Settings Settings(导演) • 定义根项目名称 • 包含/排除子项目 • 动态包含项目 • 项目路径映射 Project(演员) • 核心属性:name, version, group • 核心方法:apply, dependencies • subprojects / allprojects • 任务定义与配置 多项目构建结构 根项目(统筹) → 子项目(独立模块) → 统一配置(subprojects) → 跨项目依赖(project()) 跨项目配置方式 project() 方法 | configure() 方法 | 跨项目依赖 | Settings 中配置项目

这张图把本章的核心内容串了起来。你从上往下看:Settings 决定哪些项目参与构建,Project 负责具体的构建逻辑,多项目结构把它们组织起来,跨项目配置则让它们能够协同工作。

我的建议:刚开始接触多项目构建时,不要追求花哨的配置。先把 settings.gradle 和根项目的 build.gradle 写好,让子项目能正常编译、依赖。等熟悉了,再慢慢尝试动态包含、跨项目配置这些高级特性。

好了,这一章的内容就到这里。Project 和 Settings 是 Gradle 构建的基石,理解了它们,你就能真正掌控 Gradle,而不是被 Gradle 牵着走。


公众号:蓝海资料掘金营,微信deep3321