Koin — 什么是依赖注入原则以及它是如何工作的

作者: IT Sectr 发布日期: 2026-05-04 阅读时间: 8 分钟

Koin是一个面向Kotlin的DI框架,无需代码生成、反射和注解即可运行。该库使用DSL来描述模块,并通过轻量级容器注入依赖项,支持Android、Ktor和Multiplatform。根据Koin官方文档,该框架提供模块、作用域以及对Jetpack Compose的内置支持,具有最少的样板代码

要点

  • Koin——面向Kotlin的DI框架,使用DSL,无需反射和代码生成。
  • 模块——通过single和factory函数对依赖项注册进行逻辑分组。
  • single——单例注册,其实例只创建一次。
  • factory——每次请求都会创建新实例的注册方式。
  • Scope——将依赖项的生命周期绑定到组件(例如Activity)的机制。

什么是Koin及其区别

Koin——面向Kotlin的DI框架,使用纯语言编写,无需反射、注解或代码生成。与需要注解处理器和编译时代码生成的Dagger Hilt不同,Koin完全在运行时使用轻量级DSL来描述模块。

Koin的主要理念是提供简单的API来注册和解析依赖项,无需学习复杂的依赖关系图和组件树概念。开发人员描述哪些类可供容器使用,Koin通过构造器或惰性by inject委托自动注入它们。该框架与Kotlin Multiplatform完全兼容,允许在Android、iOS和服务器端使用统一的DI方法。

根据Kotlin开发者社区调查(2025年),Koin被用于31%的商业Android项目中,在流行度上仅次于Hilt(47%)。选择的主要原因是配置简单且无需代码生成,从而加快了项目构建速度。

对于需要快速启动开发的中大型项目,或者由于架构原因无法使用Hilt的Kotlin Multiplatform解决方案,请选择Koin。

Koin不使用反射和代码生成——所有注册都基于带有reified类型的内联函数,这些函数在编译阶段将具体类型替换到函数体中。这使得Koin成为最终APK大小方面最轻量的DI框架之一:添加Koin只会使应用程序大小增加100–150 KB,而Dagger Hilt由于生成的代码会增加约500 KB。

Koin容器和DSL的工作原理

Koin容器通过startKoin函数初始化,该函数接受带有配置的lambda。在此lambda内部,描述了带有注册的模块——DI逻辑的主要构建块。

startKoin和模块

startKoin函数创建一个通过GlobalContext从应用程序任何位置都可访问的全局容器,但在多模块项目中建议使用KoinApplication创建隔离的容器。在Android中,初始化使用AndroidContext,它会自动绑定到Application的生命周期。模块通过modules参数注册,该参数接受Module实例的列表。

kotlin
val networkModule = module {
    single {
        OkHttpClient()
    }
    single {
        Retrofit.Builder()
            .baseUrl("https://api.example.com")
            .build()
    }
}

startKoin {
    modules(networkModule)
}

每个模块包含通过single(单例)或factory(新实例)的定义。定义可以通过get()引用其他已注册的依赖项,形成注入图,无需显式指定类型和样板代码。

DSL和内联函数

Koin积极使用带有reified参数的内联函数从上下文中推断类型。这允许在不显式指定类的情况下编写注册:single { MyService() }根据lambda的返回值自动确定类型。

与Dagger不同,Koin不在编译时检查依赖关系图——所有错误都在运行时首次访问未解析的依赖项时被发现。这是一种折衷方案,它显著简化了代码并加快了构建速度,但需要DI配置的测试覆盖。

在Koin 3.5版本中,通过Koin Annotations插件引入了编译时图检查的实验性功能。然而,Koin的主要优势——无需代码生成——在这种模式下会丢失,因此大多数团队继续使用经典的DSL方法,通过测试进行运行时检查。

Koin中的依赖注入方式

Koin提供了几种依赖注入方式:by inject()、get()以及通过构造函数直接传递。方式的选择取决于使用上下文。

by inject()——惰性注入

by inject委托——在ViewModel和Android片段中最常见的注入方式。依赖项被惰性初始化——仅在首次访问属性时。这对于可能不需要立即使用的资源密集型服务是高效的。

kotlin
class MainViewModel : ViewModel() {
    private val repository: UserRepository by inject()

    fun loadUsers() {
        repository.fetchAll()
    }
}

get()——显式获取

get函数立即返回依赖项的实例。与by inject()不同,get()不支持惰性加载,并且要求容器在调用时已经初始化。

Koin中的模块和作用域

Scope在Koin中——将依赖项的生命周期绑定到特定组件(如Activity、Fragment或用户会话)的机制。

scope——绑定到组件

模块内的scope函数创建一个作用域,该作用域在关联组件存活期间存在。作用域中注册的所有依赖项在关闭时被销毁,防止内存泄漏。

kotlin
val userScope = module {
    scope<UserSession> {
        scoped {
            UserRepository(get())
        }
        scoped {
            SessionManager(get())
        }
    }
}

scoped函数注册仅存在于作用域内的依赖项。

single vs factory

single——为整个应用程序注册单个实例,具有惰性初始化。factory——每次get()调用创建新实例,用于ViewModel、存储库和有状态对象。

Koin在Android项目中的应用

Koin集成到Android项目中非常简单:只需在build.gradle中添加依赖项并在Application.onCreate中调用startKoin即可。Koin提供用于与Jetpack Compose、Navigation和WorkManager集成的模块。

专门的koin-android-compose库允许通过koinViewModel()和koinInject()函数直接在Composable函数中注入依赖项。

根据Google I/O 2024,Jetpack Compose已成为新Android项目的主要框架。Koin无需额外配置即可提供对Compose的原生支持。

对于测试,Koin提供koinTest和koinTestRule函数,这些函数创建带有测试模块的隔离测试容器。与Jetpack Navigation的集成通过koin-androidx-navigation模块实现。

使用Koin进行ViewModel单元测试时,使用koin-test-junit5或koin-test-junit4库中的koinTestRule。实际依赖项通过MockK替换为模拟对象。

Koin 3.x的关键功能之一是支持Ktor在Kotlin中创建服务器应用程序,以及支持Compose Multiplatform创建桌面应用程序。这使得Koin成为唯一一个在不改变注入范式的情况下覆盖所有三个Kotlin平台的DI框架。

对于多模块项目,Koin通过loadKoinModules支持模块的惰性加载,允许每个功能模块独立连接DI配置。

常见问题

Koin与Dagger Hilt有何不同?

Koin在运行时工作,无需代码生成和注解,这加快了构建速度,但不在编译时检查依赖关系图。Hilt在编译时生成代码并更早地检测到DI错误,但需要复杂的配置并减慢构建速度。

Koin支持Kotlin Multiplatform吗?

是的,Koin完全支持Kotlin Multiplatform。koin-core库在所有Kotlin平台上运行。

如何处理Koin中的循环依赖?

循环依赖会导致运行时StackOverflowError。Koin不会自动检测它们。解决方案是重构架构。

是否需要手动关闭作用域?

在Android中,作用域可以通过AndroidScope绑定到Activity或Fragment的生命周期。组件销毁时,Koin会自动关闭相应的作用域。

如何测试使用Koin的代码?

使用koin-test模块中的koinTest函数。它会创建一个带有测试模块的隔离容器,该容器在测试后自动关闭。

总结

  • Koin——面向Kotlin的DI框架,使用DSL,无需反射、注解和代码生成。
  • 模块通过single(单例)和factory(新实例)对注册进行分组。
  • startKoin初始化通过by inject()和get()可访问的全局容器。
  • Scope将依赖项的生命周期绑定到Android组件的生命周期。
  • Compose中的注入通过koinViewModel()和koinInject()完成。
  • Koin支持Kotlin Multiplatform,允许在所有平台上使用统一的DI方法。
  • DI错误在运行时检测到,因此配置的测试覆盖是强制性的。

我们将开发一款交钥匙移动应用程序

IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。

讨论项目

另请阅读