Skip to content

Koin: 纯 Kotlin 依赖注入框架 Koin 4.0+

源:Koin 官方文档 | Koin 中文文档 (第三方翻译)

Koin 是一款专为 Kotlin 开发者设计的轻量级依赖注入(DI)框架。不同于 Dagger 或 Hilt 依赖复杂的 APT(注解处理)或代码生成技术,Koin 完全基于 Kotlin 的 DSL(领域特定语言)内联函数 实现。它以极简的配置、极快的编译速度以及天然的跨平台(KMP)支持,成为现代化 Android 开发中替代沉重 DI 方案的首选。

技术价值与选型对比

  • 无代码生成:不使用注解处理器,这意味着更快的编译速度和更简单的调试体验。
  • DSL 驱动:利用 Kotlin 的强类型特性,通过 module { ... } 块清晰地声明依赖关系。
  • 原生 Android 适配:提供了对 ViewModelFragment 生命周期以及 SavedStateHandle 的深度集成。
  • 跨平台一致性:核心逻辑在 Android、iOS 和 JVM 之间高度一致,是 KMP 架构的核心 DI 选择。

依赖配置与版本

查看 Maven Central 最新版本

kotlin
dependencies {
    // Koin 核心库 (KMP 基础)
    implementation("io.insert-koin:koin-core:4.0.0")
    // Android 支持 (包含 ViewModel 注入)
    implementation("io.insert-koin:koin-android:4.0.0")
    // Compose 深度集成支持
    implementation("io.insert-koin:koin-androidx-compose:4.0.0")
}
groovy
dependencies {
    implementation 'io.insert-koin:koin-core:4.0.0'
    implementation 'io.insert-koin:koin-android:4.0.0'
    implementation 'io.insert-koin:koin-androidx-compose:4.0.0'
}
toml
[versions]
koin = "4.0.0"

[libraries]
koin-core = { group = "io.insert-koin", name = "koin-core", version.ref = "koin" }
koin-android = { group = "io.insert-koin", name = "koin-android", version.ref = "koin" }
koin-compose = { group = "io.insert-koin", name = "koin-androidx-compose", version.ref = "koin" }

核心原语:Module、Single 与 Factory

Koin 的依赖声明非常直观,主要通过模块(Module)进行组织。

API 核心签名

kotlin
public fun module(
    createdAtStart: Boolean = false, 
    moduleDefinition: ModuleDefinition
): Module

public inline fun <reified T> Module.single(
    qualifier: Qualifier? = null,
    createdAtStart: Boolean = false,
    noinline definition: Definition<T>
): KoinDefinition<T>

public inline fun <reified T> Module.factory(
    qualifier: Qualifier? = null,
    noinline definition: Definition<T>
): KoinDefinition<T>

依赖注入实战

模块声明与初始化

kotlin
val appModule = module {
    // 声明一个单例 (Singleton)
    single<ApiService> { ApiServiceImpl(get()) }
    
    // 声明一个工厂模式 (每次获取都是新实例)
    factory { UserRepository(get()) }
    
    // 声明 ViewModel (自动处理生命周期)
    viewModel { MainViewModel(get()) }
}
kotlin
class MyApp : Application() {
    override fun onCreate() {
        super.onCreate()
        startKoin {
            androidContext(this@MyApp)
            modules(appModule)
        }
    }
}

在组件中使用

Koin 提供了极其优雅的委托属性进行注入。

kotlin
class MainActivity : AppCompatActivity() {
    // 惰性注入:仅在第一次访问时初始化
    private val viewModel: MainViewModel by viewModel()
    
    // 普通对象注入
    private val repository: UserRepository by inject()
}

底层原理:运行时加载与服务定位器

不同于 Dagger 的图遍历(Graph Traversal),Koin 本质上是一个类型安全的 服务定位器(Service Locator)

依赖查找机制

  1. Registry 注册:当执行 startKoin 时,Koin 将所有 module 中的定义(Definitions)存入一个内部的映射表中(Instance Registry)。
  2. 动态解析:当你调用 get()by inject() 时,Koin 会根据泛型 T 查找对应的定义。
  3. 内联函数黑魔法:利用 reified 关键字,Koin 能在运行时保留泛型信息,从而实现无反射的类型查找。
深度剖析:Koin 如何解决循环依赖问题?

Koin 采用的是“即时求值”策略。

  • A 依赖 BB 依赖 A 时,Koin 会在运行时抛出 StackOverflowError 或明确的循环依赖异常。
  • 建议:通过 get() 的顺序化定义来规避大部分循环,或者使用 Property 注入(不推荐)来打破强依赖关系。

工程实践准则

模块化拆分

对于大型 Android 项目,应根据业务功能拆分不同的 appModulenetworkModulefeatureModule,并利用 loadKoinModules 在 Feature 模块内按需加载。

生产环境混淆 (R8)

由于 Koin 依赖于运行时的类名查找(虽然使用了 reified,但部分场景仍涉及),需保留相关类:

proguard
# 保留 Koin 内部逻辑
-keep class org.koin.** { *; }
# 保留注入对象的构造函数 (防止 R8 移除未直接引用的构造函数)
-keepclassmembers class * {
    public <init>(...);
}

测试支持

Koin 提供了强大的 KoinTest 接口,允许你在单元测试中通过 declareMock<T> 轻松替换真实的依赖为 MockK 实例,实现纯净的隔离测试。