引言:为什么在 Kotlin 中使用单体仓库?
\n在现代 Kotlin 开发中,经常面临一个两难选择:是将多个相关项目(后端、微服务、库、Android 应用)存储在单独的仓库(多仓库)中,还是将它们合并到一个单体仓库中。单体仓库是一种代码存储策略,所有组件都位于一个统一的版本控制系统中。对于 Kotlin 项目来说,由于 Gradle 强大的构建系统和对多模块的内置支持,这一点尤为重要。
\n在本文中,我们将探讨使用 Kotlin 组织单体仓库的实践方面:从目录结构到 CI/CD 配置和依赖管理。您将学习如何避免常见错误,并从统一的代码存储库中获得最大收益。
\n\n1. 单体仓库结构:从理论到实践
\n正确的结构是成功单体仓库的基础。考虑一个典型项目,包括基于 Ktor 的 REST API、一个数据库操作库和一个 Android 应用。以下是推荐的层次结构:
\nmy-monorepo/\n├── build.gradle.kts # 根构建文件\n├── settings.gradle.kts # 模块配置\n├── gradle.properties # 公共属性\n├── gradle/\n│ └── libs.versions.toml # 版本目录\n├── libs/ # 公共库\n│ ├── common-utils/ # 工具类、扩展\n│ ├── common-db/ # 数据库操作 (Exposed)\n│ └── common-dto/ # 数据传输对象\n├── services/ # 服务端应用\n│ ├── user-service/ # 用户微服务\n│ └── order-service/ # 订单微服务\n└── apps/ # 客户端应用\n └── android-app/ # Android 应用\n\n关键元素是 settings.gradle.kts。它包含所有模块:
rootProject.name = "my-monorepo"\n\ninclude("libs:common-utils")\ninclude("libs:common-db")\ninclude("libs:common-dto")\ninclude("services:user-service")\ninclude("services:order-service")\ninclude("apps:android-app")\n\n这种结构使得在服务和客户端之间轻松重用代码,并集中管理依赖版本。
\n\n1.1. 版本目录:依赖管理
\n在单体仓库中,避免库版本重复至关重要。使用 Version Catalog(文件 gradle/libs.versions.toml):
[versions]\nkotlin = "2.0.21"\nktor = "3.0.3"\nexposed = "0.57.0"\n\n[libraries]\nktor-server-core = { module = "io.ktor:ktor-server-core", version.ref = "ktor" }\nexposed-core = { module = "org.jetbrains.exposed:exposed-core", version.ref = "exposed" }\n\n[plugins]\nkotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }\n\n现在,在任何模块中,您都可以编写:
\ndependencies {\n implementation(libs.ktor.server.core)\n implementation(libs.exposed.core)\n}\n\n这确保了所有模块使用相同的版本,并简化了批量更新。
\n\n2. 模块的实践组织:Gradle 多项目
\n单体仓库中的每个模块都是一个独立的 Gradle 子项目,带有自己的 build.gradle.kts。以 common-utils 库的配置为例:
// libs/common-utils/build.gradle.kts\nplugins {\n alias(libs.plugins.kotlin.jvm)\n}\n\ngroup = "com.mycompany.common"\nversion = "1.0.0"\n\ndependencies {\n implementation(kotlin("stdlib"))\n implementation(libs.kotlinx.coroutines)\n}\n\n以下是一个基于 Ktor 的典型微服务:
\n// services/user-service/build.gradle.kts\nplugins {\n alias(libs.plugins.kotlin.jvm)\n alias(libs.plugins.ktor)\n}\n\ndependencies {\n implementation(project(":libs:common-utils"))\n implementation(project(":libs:common-dto"))\n impl