Gradle多项目构建
# Gradle 多项目构建
多项目构建(Multi-project Build)是 Gradle 的强项。与 Maven 的父子 POM 继承不同,Gradle 通过 settings.gradle 的 include 声明子项目,结构更扁平、更灵活。
# Maven 多模块 vs Gradle 多项目
| 对比项 | Maven | Gradle |
|---|---|---|
| 组织方式 | 父子 POM 继承 | settings.gradle + include |
| 公共配置 | 父 POM <dependencies> / <dependencyManagement> | 根 build.gradle 的 subprojects {} |
| 模块间依赖 | <dependency> + <type>pom</type> | project(':module') |
| 构建顺序 | Reactor 自动排序 | Task 依赖图自动排序 |
| 灵活性 | 低,固定继承链 | 高,可按需配置 |
# 项目结构
# 典型多项目结构
my-project/
├── settings.gradle # 声明所有子项目
├── build.gradle # 根项目构建脚本(公共配置)
├── gradle.properties # 全局属性
├── gradle/
│ └── libs.versions.toml # 统一版本管理
├── app/ # 子项目:应用主模块
│ ├── build.gradle
│ └── src/
├── common/ # 子项目:公共模块
│ ├── build.gradle
│ └── src/
└── shared/ # 子项目:共享模块
├── build.gradle
└── src/
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# interview-guide 项目结构
interview-guide 是一个简单的多项目结构,目前只有一个子项目 app:
interview-guide/
├── settings.gradle # include('app')
├── gradle.properties
├── gradle/
│ └── libs.versions.toml
└── app/ # 唯一的子项目
├── build.gradle
└── src/
2
3
4
5
6
7
8
# settings.gradle 配置
settings.gradle 是多项目构建的入口,声明项目包含哪些子项目。
# 基本用法
// 声明根项目名称
rootProject.name = 'my-project'
// 声明子项目
include('app', 'common', 'shared')
2
3
4
5
# interview-guide 的配置
pluginManagement {
repositories {
maven { url = uri('https://maven.aliyun.com/repository/public/') }
maven { url = uri('https://maven.aliyun.com/repository/gradle-plugin/') }
gradlePluginPortal()
}
}
plugins {
id 'org.gradle.toolchains.foojay-resolver-convention' version '1.0.0'
}
rootProject.name = 'interview-guide'
include('app')
2
3
4
5
6
7
8
9
10
11
12
13
14
# include 路径规则
include 的参数是项目路径,用冒号 : 分隔,对应目录层级:
// 平级子项目
include('app', 'common', 'shared')
// 对应目录:app/、common/、shared/
// 嵌套子项目
include('app:web', 'app:core')
// 对应目录:app/web/、app/core/
// 混合
include('app', 'app:web', 'app:core', 'shared')
2
3
4
5
6
7
8
9
10
include('app:web')中的app不需要单独include,Gradle 会自动创建中间项目。
# 自定义项目路径
默认情况下,include('app') 对应 app/ 目录。如果目录名和项目名不一致,可以用 project() 自定义:
include('app')
project(':app').projectDir = file('my-application-dir')
2
# 根 build.gradle 配置
根项目的 build.gradle 用于配置所有子项目的公共设置。
# subprojects 块
subprojects {} 对所有子项目应用配置:
// 根 build.gradle
subprojects {
// 应用 Java 插件
apply plugin: 'java'
// 统一 group 和 version
group = 'com.example'
version = '1.0.0'
// 统一仓库
repositories {
mavenCentral()
}
// 统一 JDK 版本
java {
toolchain {
languageVersion = JavaLanguageVersion.of(21)
}
}
// 统一编码
tasks.withType(JavaCompile).configureEach {
options.encoding = 'UTF-8'
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# allprojects 块
allprojects {} 对根项目和所有子项目都应用配置:
allprojects {
repositories {
mavenCentral()
}
}
2
3
4
5
# subprojects vs allprojects
| 块 | 作用范围 |
|---|---|
allprojects {} | 根项目 + 所有子项目 |
subprojects {} | 仅所有子项目(不含根项目) |
通常
repositories放在allprojects,插件和依赖配置放在subprojects。
# 子项目 build.gradle
每个子项目有自己的 build.gradle,可以声明项目特有的配置。
# 基本结构
// app/build.gradle
plugins {
id 'java'
id 'org.springframework.boot'
}
dependencies {
implementation project(':common') // 依赖其他子项目
implementation 'org.springframework.boot:spring-boot-starter-web'
}
2
3
4
5
6
7
8
9
10
# 项目间依赖
用 project(':子项目名') 声明子项目间的依赖:
// app/build.gradle
dependencies {
// app 依赖 common 模块
implementation project(':common')
// app 依赖 shared 模块
implementation project(':shared')
}
2
3
4
5
6
7
8
Gradle 会自动处理构建顺序:先构建
common和shared,再构建app。
# implementation project vs api project
与外部依赖一样,子项目依赖也有 implementation 和 api 的区别:
dependencies {
// common 的 API 不暴露给 app 的下游
implementation project(':common')
// common 的 API 暴露给 app 的下游
api project(':common')
}
2
3
4
5
6
7
# 公共依赖管理
# 在根项目中统一管理
// 根 build.gradle
subprojects {
dependencies {
// 所有子项目都依赖 Lombok
compileOnly libs.lombok
annotationProcessor libs.lombok
// 所有子项目都使用 JUnit 5
testImplementation libs.junit.jupiter
}
}
2
3
4
5
6
7
8
9
10
11
# 使用 Version Catalog 统一版本
Version Catalog(libs.versions.toml)对所有子项目自动可见,无需额外配置:
// app/build.gradle
dependencies {
implementation libs.tika.core
implementation libs.springdoc
}
2
3
4
5
// common/build.gradle
dependencies {
implementation libs.lombok
}
2
3
4
Version Catalog 是多项目版本管理的最佳实践,替代了 Maven 的父 POM
<dependencyManagement>。
# convention plugin(约定插件)
对于复杂的多项目结构,推荐使用 convention plugin(约定插件)来封装公共配置,而不是在根 build.gradle 中用 subprojects {}。
# 创建 convention plugin
在 buildSrc 目录下创建自定义插件:
项目根目录/
├── buildSrc/
│ ├── build.gradle
│ └── src/
│ └── main/
│ └── groovy/
│ └── com.example/
│ └── JavaConventionPlugin.groovy
├── settings.gradle
└── app/
└── build.gradle
2
3
4
5
6
7
8
9
10
11
buildSrc/build.gradle:
plugins {
id 'groovy-gradle-plugin'
}
2
3
JavaConventionPlugin.groovy:
package com.example
import org.gradle.api.Plugin
import org.gradle.api.Project
class JavaConventionPlugin implements Plugin<Project> {
void apply(Project project) {
project.with {
apply plugin: 'java'
java {
toolchain {
languageVersion = JavaLanguageVersion.of(21)
}
}
tasks.withType(JavaCompile).configureEach {
options.encoding = 'UTF-8'
}
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
app/build.gradle:
plugins {
id 'com.example.java-convention'
id 'org.springframework.boot'
}
2
3
4
convention plugin 的优势:配置可复用、可测试、可版本管理,比
subprojects {}更清晰。适合 3 个以上子项目的场景。
# 构建顺序
Gradle 根据 Task 依赖关系自动确定构建顺序:
app 依赖 common
→ 构建 common(compileJava → jar)
→ 构建 app(compileJava → jar,classpath 中包含 common 的 jar)
2
3
# 查看构建顺序
# 查看所有项目
gradlew projects
# 查看某项目的 Task
gradlew :app:tasks
# Dry-run 查看 Task 执行计划
gradlew build --dry-run
2
3
4
5
6
7
8
# 多项目构建命令
| 命令 | 说明 |
|---|---|
gradlew build | 构建所有子项目 |
gradlew :app:build | 只构建 app 子项目 |
gradlew :app:bootRun | 运行 app 子项目 |
gradlew :common:test | 只测试 common 子项目 |
gradlew :app:dependencies | 查看 app 的依赖树 |
gradlew projects | 列出所有项目 |
gradlew build --parallel | 并行构建所有子项目 |
# 只构建变更的模块
Gradle 的增量构建会自动跳过未变更的 Task。配合 --configure-on-demand 可以只配置参与构建的模块:
gradlew :app:build --configure-on-demand
# 实际项目示例
# interview-guide 的多项目配置
interview-guide 目前是单子项目结构,但已具备多项目的基础:
settings.gradle:
rootProject.name = 'interview-guide'
include('app')
2
app/build.gradle:
plugins {
id 'java'
alias(libs.plugins.spring.boot)
alias(libs.plugins.spring.dependency.management)
}
group = 'com.interview'
version = '0.0.1-SNAPSHOT'
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-webmvc'
runtimeOnly 'org.postgresql:postgresql'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
2
3
4
5
6
7
8
9
10
11
12
13
14
# 扩展为多项目
如果 interview-guide 需要拆分出公共模块,只需:
1. 创建目录和构建脚本:
interview-guide/
├── settings.gradle
├── app/
│ └── build.gradle
└── common/ # 新增公共模块
└── build.gradle
2
3
4
5
6
2. 修改 settings.gradle:
rootProject.name = 'interview-guide'
include('app', 'common') // 新增 common
2
3. common/build.gradle:
plugins {
id 'java'
}
group = 'com.interview'
version = '0.0.1-SNAPSHOT'
dependencies {
compileOnly libs.lombok
annotationProcessor libs.lombok
}
2
3
4
5
6
7
8
9
10
11
4. app/build.gradle 依赖 common:
dependencies {
implementation project(':common') // 依赖公共模块
implementation 'org.springframework.boot:spring-boot-starter-webmvc'
// ...
}
2
3
4
5
5. 根 build.gradle 统一公共配置(可选):
subprojects {
group = 'com.interview'
version = '0.0.1-SNAPSHOT'
java {
toolchain {
languageVersion = JavaLanguageVersion.of(25)
}
}
tasks.withType(JavaCompile).configureEach {
options.encoding = 'UTF-8'
options.release = 25
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
拆分模块后,
app中的公共代码移到common,app通过project(':common')引用。
# Maven 迁移注意事项
从 Maven 多模块迁移到 Gradle 多项目时,注意以下几点:
| Maven 概念 | Gradle 对应 | 注意事项 |
|---|---|---|
| 父 POM | 根 build.gradle + subprojects {} | 不需要父 POM 打包类型为 pom |
<modules> | include() | 在 settings.gradle 中声明 |
<parent> 继承 | subprojects {} 或 convention plugin | Gradle 无显式继承概念 |
<dependencyManagement> | Version Catalog | 用 TOML 文件管理 |
模块间 <dependency> | project(':module') | 用项目路径引用 |
| Reactor 构建顺序 | Task 依赖图 | 自动排序,无需手动指定 |