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 实例,然后把脚本里的代码委托给这个实例执行。
嗯,这里要注意:你写的 dependencies、repositories、task,其实都是在调用 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():对当前项目及所有子项目统一配置
你想想看,subprojects 和 allprojects 这两个方法,是多项目构建的利器。比如你想让所有子项目都使用同一个仓库:
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() 方法
如果你需要对一组项目做相同配置,configure 比 project 更合适:
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 会自动处理构建顺序:先构建 core 和 common,再构建 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 知识体系总览
为了让你更直观地理解本章的知识结构,我画了一张图:
这张图把本章的核心内容串了起来。你从上往下看:Settings 决定哪些项目参与构建,Project 负责具体的构建逻辑,多项目结构把它们组织起来,跨项目配置则让它们能够协同工作。
我的建议:刚开始接触多项目构建时,不要追求花哨的配置。先把 settings.gradle 和根项目的 build.gradle 写好,让子项目能正常编译、依赖。等熟悉了,再慢慢尝试动态包含、跨项目配置这些高级特性。
好了,这一章的内容就到这里。Project 和 Settings 是 Gradle 构建的基石,理解了它们,你就能真正掌控 Gradle,而不是被 Gradle 牵着走。
公众号:蓝海资料掘金营,微信deep3321