主题
第 4 章 构建脚本 DSL:Groovy vs Kotlin
学习目标:搞清楚
build.gradle(Groovy)和build.gradle.kts(Kotlin)的区别;掌握两种 DSL 的 50+ 种常见写法对照;能把任何 Groovy 脚本无损翻译成 Kotlin 脚本;理解 settings 文件、properties 文件、Version Catalog 各自的职责。
4.1 两种 DSL 的"基因"
4.1.1 它们是什么?
┌─────────────────────────────────────────────────────────┐
│ Groovy DSL Kotlin DSL │
│ ──────────── ────────── │
│ 文件后缀: .gradle 文件后缀: .gradle.kts │
│ 语言: Groovy 语言: Kotlin │
│ 类型: 动态类型 类型: 静态类型 │
│ IDE 提示: 弱 IDE 提示: 完整 │
│ 执行: Groovy AOT编译 执行: Kotlin 编译为字节码 │
│ 起步速度: ★★★★ 起步速度: ★★★ │
│ 语法简洁: ★★★★★ 语法简洁: ★★★★ │
│ 错误检测: 运行时 错误检测: 编译时 │
│ 推荐场景: 老项目维护 推荐场景: 新项目首选 │
└─────────────────────────────────────────────────────────┘4.1.2 同一段代码两种写法
groovy
// build.gradle (Groovy)
plugins {
id 'java'
id 'org.springframework.boot' version '3.2.0'
}
group = 'com.example'
version = '1.0.0'
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
test {
useJUnitPlatform()
}kotlin
// build.gradle.kts (Kotlin)
plugins {
java
id("org.springframework.boot") version "3.2.0"
}
group = "com.example"
version = "1.0.0"
repositories {
mavenCentral()
}
dependencies {
implementation("org.springframework.boot:spring-boot-starter-web")
testImplementation("org.springframework.boot:spring-boot-starter-test")
}
tasks.test {
useJUnitPlatform()
}📌 核心观察:差别不大。Kotlin 多了一些括号和引号;Groovy 可以省略很多语法糖。但 Kotlin 在 IDE 里每个属性都能跳转,Groovy 大部分是"哑的"。
4.2 Groovy DSL 速查(看老项目用)
4.2.1 Groovy 的"省略大法"
Groovy DSL 之所以看起来短,靠的是大量语法省略:
groovy
// 1. 调方法可以省括号
println('hi')
println 'hi'
// 2. 字符串单引号 / 双引号都行(双引号支持 ${} 插值)
def name = 'Alice'
println "Hello, ${name}"
// 3. 闭包是"最后一个参数"时可以放在括号外
list.each({ println it })
list.each { println it }
// 4. 整段配置 = 调方法 + 传闭包
dependencies {
implementation 'guava' // 等价于 dependencies({ implementation('guava') })
}4.2.2 Groovy 经常踩的坑
groovy
// ❌ 漏 def,结果意外创建了"全局变量"
project.ext {
foo = 'a' // 实际定义了 ext.foo
bar = 'b' // 实际定义了 ext.bar
}
def baz = 'c' // 这才是真正的局部变量
// ❌ 字符串拼接拼错了引号类型
def url = 'https://repo.example.com/${project.name}' // ← 单引号!${} 不会被替换
def url = "https://repo.example.com/${project.name}" // ← 双引号才行
// ❌ 误用 = 给 task 属性赋值
task foo {
description = 'this is foo' // 这是配置 task
enabled = false // 这也是配置 task
// 但下面这行:
something // ← 找不到属性名 something,但 Groovy 不会立刻报错
}📌 建议:Groovy DSL 维护老项目时多用 IDEA 的"Convert to Kotlin DSL"功能(IDEA 2023.x+ 已经支持),然后在 Kotlin 上编辑,更安全。
4.3 Kotlin DSL 速查(新项目首选)
4.3.1 Kotlin DSL 的核心特性
kotlin
// 1. 调方法必须括号、字符串必须双引号
println("hi")
// 2. 闭包语法 = lambda
list.forEach { println(it) }
// 3. dependencies 块 → 调用 Project.dependencies(Action<DependencyHandlerScope>)
dependencies {
implementation("guava")
}
// 4. 类型安全访问器(Type-safe accessors)—— 由插件生成
plugins {
java // ← java 不是字符串,是一个 PluginAccessor
`maven-publish` // 中划线插件名要用反引号
}
java { // ← 这里的 java 来自 java 插件提供的 extension
toolchain {
languageVersion = JavaLanguageVersion.of(17)
}
}4.3.2 Kotlin DSL 的"4 大写法"
kotlin
// 写法 1:直接配置 extension(最常见)
java {
sourceCompatibility = JavaVersion.VERSION_17
}
// 写法 2:tasks.named —— 配置已存在的 task(懒求值)
tasks.named<Test>("test") {
useJUnitPlatform()
maxParallelForks = 4
}
// 写法 3:tasks.register —— 注册新 task(懒求值)
tasks.register<Copy>("copyDocs") {
from("docs")
into(layout.buildDirectory.dir("docs"))
}
// 写法 4:tasks.withType —— 配置某种类型的所有 task
tasks.withType<Test>().configureEach {
useJUnitPlatform()
}4.3.3 Kotlin DSL 的"加分写法"
kotlin
// 1. configureEach(强烈推荐):lazy + 适用于所有当前和未来的 task
tasks.withType<JavaCompile>().configureEach {
options.encoding = "UTF-8"
}
// 2. extension lazy access —— extensions.getByName<XxxExtension>("xxx")
val springBoot = extensions.getByName<SpringBootExtension>("springBoot")
// 3. provider / property API(lazy + Configuration Cache 友好)
val outputFile = layout.buildDirectory.file("output.txt") // 返回 Provider
tasks.register("write") {
outputs.file(outputFile)
doLast {
outputFile.get().asFile.writeText("Hello")
}
}4.4 Groovy ⇄ Kotlin 完整对照表
4.4.1 基础语法
| 场景 | Groovy DSL | Kotlin DSL |
|---|---|---|
| 字符串 | 'hello' 或 "hello" | "hello"(必须双引号) |
| 字符串插值 | "Hello $name" | "Hello $name" |
| 调方法 | println 'hi' | println("hi") |
| 列表 | def list = [1, 2, 3] | val list = listOf(1, 2, 3) |
| Map | [a: 1, b: 2] | mapOf("a" to 1, "b" to 2) |
| 闭包 | { x -> x * 2 } | { x -> x * 2 } |
4.4.2 项目元数据
| 场景 | Groovy | Kotlin |
|---|---|---|
| 项目名 | rootProject.name = 'foo' | rootProject.name = "foo" |
| group | group 'com.example' | group = "com.example" |
| version | version '1.0.0' | version = "1.0.0" |
4.4.3 插件
| 场景 | Groovy | Kotlin |
|---|---|---|
| 内置插件 | id 'java' | java |
| 中划线插件 | id 'java-library' | \java-library`` |
| 第三方插件 | id 'org.foo.bar' version '1.0' | id("org.foo.bar") version "1.0" |
| Kotlin 插件 | id 'org.jetbrains.kotlin.jvm' version '...' | kotlin("jvm") version "..." |
| apply(旧) | apply plugin: 'java' | apply(plugin = "java") |
4.4.4 仓库
| 场景 | Groovy | Kotlin |
|---|---|---|
| Maven Central | mavenCentral() | mavenCentral() |
google() | google() | |
| 自定义 maven | maven { url 'https://x.y/z' } | maven("https://x.y/z") |
| 带凭证 | maven { url '...'; credentials { username 'u' } } | maven { url = uri("..."); credentials { username = "u" } } |
4.4.5 依赖
| 场景 | Groovy | Kotlin |
|---|---|---|
| implementation | implementation 'g:a:v' | implementation("g:a:v") |
| testImplementation | testImplementation 'g:a:v' | testImplementation("g:a:v") |
| 模块依赖 | implementation project(':lib') | implementation(project(":lib")) |
| 文件依赖 | implementation files('libs/x.jar') | implementation(files("libs/x.jar")) |
| 排除传递 | implementation('g:a:v') { exclude group: 'x' } | implementation("g:a:v") { exclude(group = "x") } |
| 强制版本 | implementation('g:a:v!!') | implementation("g:a:v!!") |
4.4.6 任务
| 场景 | Groovy | Kotlin |
|---|---|---|
| 注册 task | task hello { doLast { println 'hi' } } | tasks.register("hello") { doLast { println("hi") } } |
| 注册 typed | task copyDocs(type: Copy) { ... } | tasks.register<Copy>("copyDocs") { ... } |
| 配置已有 | test { useJUnitPlatform() } | tasks.test { useJUnitPlatform() } 或 tasks.named<Test>("test") { ... } |
| 配置一类 | tasks.withType(Test) { ... } | tasks.withType<Test>().configureEach { ... } |
| dependsOn | task foo { dependsOn 'bar' } | tasks.register("foo") { dependsOn("bar") } |
4.4.7 文件 / 路径
| 场景 | Groovy | Kotlin |
|---|---|---|
| 项目目录 | project.projectDir | project.projectDir |
| build 目录 | project.buildDir (旧) | layout.buildDirectory.get().asFile(推荐) |
| 文件 | file('foo/bar.txt') | file("foo/bar.txt") |
| 文件树 | fileTree('src') | fileTree("src") |
| 文件集合 | files('a.txt', 'b.txt') | files("a.txt", "b.txt") |
4.4.8 扩展属性
| 场景 | Groovy | Kotlin |
|---|---|---|
| 定义 ext | ext.myProp = 'foo' | extra["myProp"] = "foo" |
| 用 ext | println myProp | println(extra["myProp"]) |
4.5 settings.gradle.kts 详解
4.5.1 它能做什么?
kotlin
// settings.gradle.kts —— 完整版示例
// 1. 项目名
rootProject.name = "my-multi-project"
// 2. 包含子模块
include("app", "lib-core", "lib-data", "feature-billing")
// 3. 改子模块路径(如果不在标准位置)
project(":feature-billing").projectDir = file("features/billing")
// 4. 插件管理:插件从哪些仓库找
pluginManagement {
repositories {
gradlePluginPortal()
google()
mavenCentral()
}
// 也可以在这里管理插件版本
plugins {
kotlin("jvm") version "1.9.20"
}
}
// 5. 依赖仓库管理:所有项目共享同一组仓库
dependencyResolutionManagement {
repositoriesMode = RepositoriesMode.FAIL_ON_PROJECT_REPOS
repositories {
mavenCentral()
google()
}
// 6. 引入 Version Catalog(强烈推荐)
versionCatalogs {
create("libs") {
from(files("gradle/libs.versions.toml"))
}
}
}
// 7. Composite Build(包含其他独立项目作为依赖源)
includeBuild("../my-shared-library")
// 8. 插件版本仓库 + 镜像
// pluginManagement.repositories.maven("https://maven.aliyun.com/repository/gradle-plugin")4.5.2 RepositoriesMode 三种模式
| 模式 | 行为 |
|---|---|
PREFER_PROJECT | 项目里定义的仓库优先(默认,但容易让多模块仓库散乱) |
PREFER_SETTINGS | 优先用 settings 里的,子项目可以再加 |
FAIL_ON_PROJECT_REPOS | 强烈推荐 —— 子项目不允许定义 repositories,必须统一在 settings |
💡 用
FAIL_ON_PROJECT_REPOS的好处:避免某个子模块偷偷加个公司私服,导致依赖供应链混乱。
4.6 gradle.properties 详解
4.6.1 它能做什么?
gradle.properties 存"全局属性",构建脚本可以读到:
properties
# 项目级属性(可在 build.gradle.kts 里以 project property 访问)
projectVersion=1.0.0
springBootVersion=3.2.0
# JVM 配置
org.gradle.jvmargs=-Xmx2g -XX:+UseG1GC -XX:MaxMetaspaceSize=512m
# 性能开关
org.gradle.parallel=true # 并行构建多模块
org.gradle.caching=true # 开启 Build Cache
org.gradle.configuration-cache=true # 开启 Configuration Cache(Gradle 7+)
org.gradle.daemon=true # 启用 Daemon(默认 true)
# Kotlin 配置
kotlin.code.style=official
kotlin.incremental=true
# Android 相关
android.useAndroidX=true
android.nonTransitiveRClass=true4.6.2 在脚本里读
kotlin
// build.gradle.kts
val springBootVersion: String by project // 读 gradle.properties 里的同名属性
dependencies {
implementation("org.springframework.boot:spring-boot-starter-web:$springBootVersion")
}4.6.3 三种 properties 文件优先级
① 命令行 -P 参数(最高) → ./gradlew build -PprojectVersion=2.0
② 项目根 gradle.properties
③ ~/.gradle/gradle.properties(用户级,最低)💡 典型用法:把 token、密码 放
~/.gradle/gradle.properties(不会进 Git),把 版本号 放项目根(要进 Git)。
4.7 Version Catalog(版本目录)—— 现代依赖管理推荐
4.7.1 痛点:版本号散落各处
老项目里:
kotlin
// app/build.gradle.kts
implementation("org.springframework.boot:spring-boot-starter-web:3.2.0")
// lib/build.gradle.kts
implementation("org.springframework.boot:spring-boot-starter-web:3.1.5") // ← 不一致!
// feature/build.gradle.kts
implementation("org.springframework.boot:spring-boot-starter-web:3.2.1") // ← 又一个版本!升级 Spring Boot 时要找遍所有 build 文件。版本散乱是大型项目的噩梦。
4.7.2 解决:libs.versions.toml
在 gradle/libs.versions.toml 集中管理:
toml
[versions]
spring-boot = "3.2.0"
kotlin = "1.9.20"
junit = "5.10.0"
guava = "32.1.3-jre"
[libraries]
spring-boot-starter-web = { module = "org.springframework.boot:spring-boot-starter-web", version.ref = "spring-boot" }
spring-boot-starter-test = { module = "org.springframework.boot:spring-boot-starter-test", version.ref = "spring-boot" }
junit-jupiter = { module = "org.junit.jupiter:junit-jupiter", version.ref = "junit" }
guava = { module = "com.google.guava:guava", version.ref = "guava" }
[plugins]
spring-boot = { id = "org.springframework.boot", version.ref = "spring-boot" }
kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
[bundles]
# 把多个常一起用的依赖打包
spring-web = ["spring-boot-starter-web", "spring-boot-starter-actuator"]在 build.gradle.kts 里用:
kotlin
plugins {
alias(libs.plugins.kotlin.jvm)
alias(libs.plugins.spring.boot)
}
dependencies {
implementation(libs.spring.boot.starter.web) // ← 类型安全!
implementation(libs.guava)
testImplementation(libs.junit.jupiter)
// 或者用 bundle:
// implementation(libs.bundles.spring.web)
}4.7.3 命名规范(重要)
libs.versions.toml 里: Kotlin DSL 访问:
spring-boot libs.versions.spring.boot
spring-boot-starter-web libs.spring.boot.starter.web ← 中划线变成点
junit-jupiter libs.junit.jupiter规则:TOML key 里的 - 在 Kotlin DSL 里变成 .,下划线 _ 不变。所以推荐统一用中划线。
4.7.4 Version Catalog 的好处
| 好处 | 说明 |
|---|---|
| 一处定义 | 所有模块共享同一份版本号 |
| 类型安全 | IDE 能补全:libs.spring.boot.starter.web |
| 重构友好 | 改版本号不用改各 build 文件 |
| 依赖锁定 | 配合 dependency-locking 可精确锁版本 |
| 可发布 | Catalog 本身可以发布给其他项目复用 |
4.8 章末小结
★ 第 4 章核心知识图谱 ★
│
┌─────────────────────┼─────────────────────┐
│ │ │
┌────▼────┐ ┌────▼────┐ ┌────▼─────┐
│ Groovy │ │ Kotlin │ │ 配套文件 │
│ DSL │ │ DSL │ ├──────────┤
├─────────┤ ├─────────┤ │ settings │
│ .gradle │ │ .gradle.│ │ properties│
│ 老项目 │ │ kts │ │ Version │
│ 动态 │ │ 新项目 │ │ Catalog │
│ 弱提示 │ │ 静态 │ │ │
│ │ │ 强提示 │ │ │
└─────────┘ └─────────┘ └──────────┘
↑
★ 多模块统一版本必备 ★🎤 4.9 章末面试题(10 道高频题)
Q1. Groovy DSL 和 Kotlin DSL 的本质区别是什么?
答:3 个核心区别:
- 语言:前者是 Groovy(动态类型),后者是 Kotlin(静态类型);
- 检错时机:Groovy 写错属性名要运行时才发现;Kotlin 编译期就报错(红线);
- IDE 体验:Kotlin DSL 智能提示完整、可重构;Groovy DSL 大部分地方"哑",靠记忆 + 文档。
第二个体现在新项目应该首选 Kotlin DSL,老项目维护可以继续 Groovy。
Q2. 为什么 .gradle.kts 文件第一次启动比 .gradle 慢?
答:因为 Kotlin DSL 是真正的 Kotlin 代码,要先编译成字节码才能执行。Groovy DSL 由 Gradle 直接解释执行(虽然 Groovy 也是 JVM 语言,但执行速度更快)。
不过 Gradle 会缓存编译结果到 .gradle/ 目录,第二次起就跟 Groovy 差不多。如果脚本经常改,差异会显著。
Q3. settings.gradle.kts 里 pluginManagement 和 dependencyResolutionManagement 分别管什么?
答:
pluginManagement:管 plugin 的来源 ——plugins { id("...") version "..." }里的插件去哪找、用哪个版本。dependencyResolutionManagement:管依赖(dependencies {})的仓库 —— 所有子项目共享一套 repositories。
为啥要分开?因为插件本身就是 jar,需要先解析才能让脚本跑起来;它跟普通依赖的解析时机不同。
Q4. Version Catalog 是什么?为什么强烈推荐用?
答:Version Catalog 是 Gradle 7+ 内置的集中式版本/依赖管理机制,把所有依赖的 group:artifact:version 统一定义到 gradle/libs.versions.toml,子模块通过 libs.xxx.yyy 类型安全引用。
好处:
- 一处定义,处处复用:升级版本只改 1 个地方;
- 类型安全:IDE 全程智能提示;
- 避免散落:杜绝同一个库出现 3 个版本号;
- 可发布:把 catalog 自身发到 Maven 仓库,多项目共享。
老项目用 ext { springBootVersion = "3.2.0" } 管版本是过时做法,现代项目应该一律用 Version Catalog。
Q5. 为什么 Kotlin DSL 里 tasks.test 比 tasks.named<Test>("test") 更简洁?
答:因为 Kotlin DSL 有 type-safe accessors(类型安全访问器) —— 当 java 插件被应用时,Gradle 会自动生成 tasks.test、tasks.compileJava 这些扩展属性,给你直接用。
tasks.named<Test>("test") 是手写访问 —— 适合:
- 插件没生成 accessor 的 task;
- 自定义 task(如
tasks.named<Copy>("myCopy")); - buildSrc 里写 convention plugin(accessor 不一定可用)。
Q6. 把一个 Groovy DSL 项目迁移到 Kotlin DSL,要注意什么?
答:5 个常见坑:
- 字符串只能用双引号:单引号在 Kotlin 是 Char。
- 方法调用必须带括号:
println "x"→println("x")。 - 赋值必须显式
=:Groovy 的version '1.0'→ Kotlin 的version = "1.0"。 - 闭包参数加
it时类型可能不匹配:Groovy 全动态,Kotlin 要看 lambda 的接收者类型。 - task 配置要用
tasks.named或tasks.<name>:不能再像 Groovy 那样test { ... }顶层调用。
💡 工具:IDEA 2023.x+ 提供 "Convert build.gradle to Kotlin DSL",能自动转大部分语法。
Q7. gradle.properties 里设置 org.gradle.parallel=true 有什么作用?
答:开启 多 Project 并行配置 + 并行执行。
- 假如你有 5 个子模块,没开并行:依次执行(A→B→C→D→E);
- 开了并行:Gradle 检测无依赖关系的模块并发跑(A、B、C 同时跑,D、E 同时跑);
- 大型项目(10+ 模块)能把构建时间压缩 30-70%。
⚠️ 要求:每个 task 要正确声明 input/output,否则并行执行可能产生冲突。
Q8. 为什么有人推荐 repositoriesMode = RepositoriesMode.FAIL_ON_PROJECT_REPOS?
答:这是 settings.gradle.kts 里的一个开关,开启后子模块不允许定义 repositories {},必须统一在 settings 里配。
好处:
- 统一仓库源 —— 避免某个子模块偷偷加个公司私服或镜像;
- 依赖供应链清晰 —— 所有依赖从可控的几个仓库下;
- 审计友好 —— 安全合规要求时容易回答"我们用了哪些仓库"。
代价:迁移老项目时,要把所有子模块的 repositories 块挪到 settings。
Q9. Version Catalog 里 bundles 是干啥的?
答:bundles = "依赖打包",把多个常一起用的依赖捆成一个引用。比如:
toml
[bundles]
spring-web-stack = ["spring-boot-starter-web", "spring-boot-starter-actuator", "spring-boot-starter-validation"]kotlin
dependencies {
implementation(libs.bundles.spring.web.stack) // 一行 = 拉 3 个依赖
}适合"配套使用的依赖组合",避免 build 文件里堆 5-6 行类似的依赖。
Q10. Kotlin DSL 和 Groovy DSL 性能差距有多大?
答:
- 首次冷启动:Kotlin DSL 比 Groovy DSL 慢 30-100% 不等(脚本越大越明显),因为要先编译 Kotlin。
- 热启动:基本一致(都被 Daemon 缓存)。
- 执行 task:完全没差别(都跑成字节码)。
结论:除非你的项目有 200+ 个 build 脚本且 CI 环境冷启动频繁,否则性能不是选择 DSL 的主要因素,可读性和类型安全更重要。
下一章 → 第 5 章 · Task 全攻略 →
🎬 可视化演示
演示加载缓慢或样式异常?点此在新标签页打开 ↗
💻 示例代码
txt
/*
* 第 4 章 · DSL 演示 — Kotlin DSL 完整示例
*
* 这个脚本展示了 Kotlin DSL 几乎所有常见写法,配合注释对照学习。
* 跑:
* ./gradlew tasks
* ./gradlew showDsl —— 打印各 DSL 写法的运行时结果
*/
// ============= 1. 应用插件 =============
plugins {
java // 内置插件直接写
`java-library` // 中划线插件用反引号
application // 内置
// id("org.springframework.boot") version "3.2.0" // 第三方插件
// kotlin("jvm") version "1.9.20" // Kotlin 插件简写
}
group = "com.example.gradle.dsl" // 用 = 赋值
version = "1.0.0-SNAPSHOT"
// ============= 2. Java 配置 =============
java {
toolchain {
languageVersion = JavaLanguageVersion.of(17)
}
withSourcesJar() // 顺手生成 sources jar
withJavadocJar() // 顺手生成 javadoc jar
}
application {
mainClass = "com.example.dsl.Main" // Provider 赋值
}
// ============= 3. 仓库 =============
repositories {
mavenCentral()
google()
// maven("https://maven.aliyun.com/repository/public") // 简化写法
maven { // 完整写法(带凭证)
url = uri("https://example.com/repo")
// credentials {
// username = "reader"
// password = "secret"
// }
}
}
// ============= 4. 依赖 =============
dependencies {
// 主代码依赖
implementation("com.google.guava:guava:32.1.3-jre")
// 库的 API(要传递给消费者)
api("org.slf4j:slf4j-api:2.0.9")
// 编译时 only
compileOnly("javax.servlet:javax.servlet-api:4.0.1")
// 运行时 only
runtimeOnly("org.postgresql:postgresql:42.7.0")
// 测试依赖
testImplementation("org.junit.jupiter:junit-jupiter:5.10.0")
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
// 排除某个传递依赖
implementation("org.springframework:spring-core:6.1.1") {
exclude(group = "commons-logging", module = "commons-logging")
}
// 模块依赖(多模块)
// implementation(project(":lib-core"))
// 本地文件
// implementation(files("libs/local.jar"))
}
// ============= 5. 配置已存在的 Task =============
tasks.test {
useJUnitPlatform()
maxParallelForks = 4
testLogging {
events("passed", "skipped", "failed")
}
}
// ============= 6. 配置一类 Task(推荐写法) =============
tasks.withType<JavaCompile>().configureEach {
options.encoding = "UTF-8"
options.compilerArgs.add("-Xlint:unchecked")
}
tasks.withType<Test>().configureEach {
systemProperty("file.encoding", "UTF-8")
}
// ============= 7. 注册新 Task =============
tasks.register<Copy>("copyDocs") {
group = "ch04-demo"
from("docs")
into(layout.buildDirectory.dir("docs"))
include("**/*.md")
}
tasks.register<Zip>("packageDocs") {
group = "ch04-demo"
dependsOn("copyDocs")
archiveFileName = "docs-" + version + ".zip"
destinationDirectory = layout.buildDirectory.dir("dist")
from(layout.buildDirectory.dir("docs"))
}
// ============= 8. 扩展属性 =============
val mySecret by extra("from-build-script")
extra["anotherKey"] = "another-value"
// 读 gradle.properties 里的属性
val springBootVersion: String by project // 必须在 gradle.properties 里定义同名属性,否则会报错
// ============= 9. 一个综合演示 task =============
tasks.register("showDsl") {
group = "ch04-demo"
description = "打印各 DSL 配置的实际运行时值"
doLast {
println("================ Kotlin DSL Demo ================")
println("project.name = " + project.name)
println("project.group = " + project.group)
println("project.version = " + project.version)
println("java target = " + java.toolchain.languageVersion.get())
println("repositories = " + repositories.map { it.name })
println("plugins applied = " + plugins.map { it::class.simpleName })
println("custom extra = " + extra["mySecret"])
println("=================================================")
}
}txt
# ===== 第 4 章 · DSL 演示 — gradle.properties =====
# 项目级属性 + JVM / 性能 / 工具链配置都放这里
# ===== 自定义属性(脚本里通过 by project 读取)=====
springBootVersion=3.2.0
kotlinVersion=1.9.20
# ===== JVM 配置 =====
# 给 Gradle 进程更多内存,否则大型项目容易 OOM
org.gradle.jvmargs=-Xmx2g -XX:+UseG1GC -XX:MaxMetaspaceSize=512m -Dfile.encoding=UTF-8
# ===== 性能优化(强烈建议开启)=====
# 多模块并行构建
org.gradle.parallel=true
# 启用 Build Cache(本地缓存)
org.gradle.caching=true
# 启用 Configuration Cache(Gradle 7+)
org.gradle.configuration-cache=true
# Daemon(默认就 true,明确写出来更清楚)
org.gradle.daemon=true
# ===== Kotlin 配置 =====
kotlin.code.style=official
kotlin.incremental=true
# ===== Android 相关(如用 Android 插件)=====
# android.useAndroidX=true
# android.nonTransitiveRClass=truetoml
# ===== 第 4 章 · DSL 演示 — Version Catalog =====
# 这是 Gradle 7+ 推荐的"统一版本管理"方案
# 所有依赖的 group:artifact:version 在这里定义,子模块通过 libs.xxx 类型安全访问
[versions]
# 核心版本号集中放这里
spring-boot = "3.2.0"
kotlin = "1.9.20"
junit = "5.10.0"
guava = "32.1.3-jre"
slf4j = "2.0.9"
[libraries]
# 单个依赖
spring-boot-starter-web = { module = "org.springframework.boot:spring-boot-starter-web", version.ref = "spring-boot" }
spring-boot-starter-actuator = { module = "org.springframework.boot:spring-boot-starter-actuator", version.ref = "spring-boot" }
spring-boot-starter-test = { module = "org.springframework.boot:spring-boot-starter-test", version.ref = "spring-boot" }
# 简短依赖(直接写版本,不引用 versions)
guava = { module = "com.google.guava:guava", version.ref = "guava" }
slf4j-api = { module = "org.slf4j:slf4j-api", version.ref = "slf4j" }
junit-jupiter = { module = "org.junit.jupiter:junit-jupiter", version.ref = "junit" }
junit-jupiter-engine = { module = "org.junit.jupiter:junit-jupiter-engine", version.ref = "junit" }
[plugins]
# 把插件也声明进来,build.gradle.kts 用 alias(libs.plugins.xxx)
spring-boot = { id = "org.springframework.boot", version.ref = "spring-boot" }
kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
[bundles]
# bundle = "依赖打包",多个常一起用的依赖打成一个引用
spring-web-stack = ["spring-boot-starter-web", "spring-boot-starter-actuator"]
testing = ["junit-jupiter", "junit-jupiter-engine"]
# 在 build.gradle.kts 里这样用:
# plugins { alias(libs.plugins.spring.boot) }
# dependencies {
# implementation(libs.spring.boot.starter.web)
# implementation(libs.bundles.spring.web.stack)
# testImplementation(libs.junit.jupiter)
# }txt
/*
* 第 4 章 · DSL 演示 — settings.gradle.kts
* 演示 settings 的所有常见配置:插件管理、依赖仓库、Version Catalog、Composite Build
*/
rootProject.name = "ch04-dsl-demo"
// ===== 1. 插件管理 =====
pluginManagement {
repositories {
gradlePluginPortal()
google()
mavenCentral()
// maven("https://maven.aliyun.com/repository/gradle-plugin")
}
// 也可以集中声明插件版本,build.gradle.kts 里只需 plugins { id("...") }
plugins {
// kotlin("jvm") version "1.9.20"
}
}
// ===== 2. 依赖仓库管理 =====
dependencyResolutionManagement {
// 强制所有依赖只从 settings 这里的 repositories 拉
// 子模块再写 repositories {} 会构建失败
repositoriesMode = RepositoriesMode.FAIL_ON_PROJECT_REPOS
repositories {
mavenCentral()
google()
// maven("https://maven.aliyun.com/repository/public")
}
// ===== 3. 引入 Version Catalog =====
versionCatalogs {
create("libs") {
from(files("gradle/libs.versions.toml"))
}
}
}
// ===== 4. 包含子模块(如有)=====
// include("app", "lib-core", "feature-billing")
// 改子模块路径
// project(":feature-billing").projectDir = file("features/billing")
// ===== 5. Composite Build =====
// includeBuild("../my-shared-library")build.gradle.kts ↗ · gradle.properties ↗ · gradle/libs.versions.toml ↗ · settings.gradle.kts ↗