3、构建脚本结构:settings.gradle.kts、build.gradle.kts、init.gradle.kts
说实话,刚接触 Gradle 的人,很容易被这三个文件搞晕。我当年第一次看到项目里同时躺着三个 .kts 文件时,心里就一个想法:到底哪个才是入口?
其实没那么复杂。这三个文件各管一摊事,分工非常明确。咱们一个一个说。
3.1 settings.gradle.kts:项目的“总指挥”
这个文件是 Gradle 构建的起点。你想想看,Gradle 启动后第一件事是什么?它得先知道:我要构建哪些模块?
这就是 settings.gradle.kts 的职责。它定义了一个多模块项目的结构。
// settings.gradle.kts
rootProject.name = "my-awesome-app"
include(":core")
include(":web")
include(":api")
这里我特别想提醒一点:模块名前面的冒号不是装饰。它代表相对于根项目的路径。比如 :core 对应的是 core/ 目录。
另外,settings.gradle.kts 里还可以配置依赖解析策略。我在一个大型微服务项目里遇到过这样的坑:不同子模块依赖了同一个库的不同版本,结果运行时各种 ClassNotFoundException。后来我在 settings 里统一做了版本锁定,问题才解决。
// 统一版本管理
dependencyResolutionManagement {
repositories {
mavenCentral()
}
versionCatalogs {
create("libs") {
from(files("gradle/libs.versions.toml"))
}
}
}
3.2 build.gradle.kts:模块的“施工图”
每个模块都有自己的 build.gradle.kts。它描述了这个模块怎么构建:用什么插件、依赖哪些库、打什么类型的包。
说白了,这就是你告诉 Gradle:“我要把这个 Kotlin 源码变成可运行的 JAR 包,中间帮我做编译、测试、打包。”
// app/build.gradle.kts
plugins {
id("org.jetbrains.kotlin.jvm") version "1.9.0"
application
}
dependencies {
implementation(project(":core"))
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3")
testImplementation(kotlin("test"))
}
application {
mainClass.set("com.example.MainKt")
}
这里有个细节:implementation 和 api 的区别。我刚开始用 Gradle 时,所有依赖全用 implementation,结果发现子模块引用不到某些类。后来才明白:api 会把依赖暴露给消费者,implementation 不会。
api。过度暴露依赖会导致编译时间变长,而且容易造成依赖冲突。我的原则是:除非子模块确实需要,否则一律用 implementation。
3.3 init.gradle.kts:全局的“初始化脚本”
这个文件比较特殊。它不放在项目目录里,而是放在 ~/.gradle/init.gradle.kts 或者 GRADLE_USER_HOME 下。
它的作用是什么?说白了,就是给所有 Gradle 构建加一层“全局配置”。比如统一设置代理、配置仓库镜像、添加全局插件。
// ~/.gradle/init.gradle.kts
allprojects {
repositories {
maven {
url = uri("https://maven.aliyun.com/repository/public")
}
}
}
我曾经在一个公司里,所有开发者的机器上都配了这么一个 init 脚本。这样大家拉下来的项目不用改任何配置,就能用内部仓库下载依赖。省了不少事。
但要注意:init.gradle.kts 不要滥用。它会影响所有构建,包括你从 GitHub 上 clone 下来的别人的项目。万一你在里面配了什么奇怪的逻辑,别人的项目可能就构建失败了。
settings.gradle.kts—— 管“有哪些模块”build.gradle.kts—— 管“每个模块怎么构建”init.gradle.kts—— 管“全局环境配置”
3.4 三者的协作关系
这三个文件不是孤立的。它们有明确的执行顺序:
- Gradle 启动,先找
init.gradle.kts,执行全局配置 - 然后找
settings.gradle.kts,确定项目结构 - 最后根据 settings 找到各个模块,执行各自的
build.gradle.kts
这个顺序很重要。比如你在 init 里配置了仓库镜像,那 settings 和 build 里引用的仓库就会走镜像。如果你在 settings 里配置了插件版本,那 build 里引用插件时就不用再写版本号了。
下面这张图可以帮你理清它们的关系:
3.5 一些实用建议
最后,分享几个我在实际项目里积累的经验:
- settings.gradle.kts 里尽量少写逻辑。 它只负责项目结构和仓库配置,别在里面写 task 定义或者复杂的条件判断。我见过有人把构建逻辑塞进 settings,结果调试起来非常痛苦。
- build.gradle.kts 保持简洁。 如果构建逻辑复杂了,抽到
buildSrc或者自定义插件里去。一个文件超过 200 行,就该考虑重构了。 - init.gradle.kts 只放“全局必须”的配置。 比如公司内部仓库镜像、统一的插件版本。别放跟具体项目相关的逻辑。
- 善用 version catalog。 在
gradle/libs.versions.toml里统一管理依赖版本,然后在 settings 里引用。这样所有模块的依赖版本都一目了然。
嗯,这三个文件的关系搞清楚了,Gradle 构建脚本的基本结构你就掌握了八成。剩下的就是在实践中慢慢积累经验了。