探索Koin框架:简单、灵活的依赖注入解决方案

最近架构优化的需要,了解了一下平时不是很愿意去了解的依赖注入框架(因为Dagger2实在是过于难用,koin以前感觉不是很成熟)。主要关注了两个框架,一个是Google基于Dagger开发的hilt框架,一个是基于Kotlin开发的koin框架。因为我们的项目里面依赖了Tinker,Hit不支持Application不使用无参构造方法,所以下定决心转去看了koin的使用。 这里我就不介绍什么是依赖注入了,如果你不了解可以网上搜到很多文章讲解这个。大致可以可以接为,给一个对象注入另一个对象就算是一种"注入",依赖注入框架只是帮助我们封装对象的创建和赋值细节,按照一定的规则去创建我们想要的对象并注入到目标对象里。

总览

koin框架是一个纯Kotlin实现,使用Kotlin DSL去描述对象注入和对象间依赖关系以及创建规则。站在使用方的角度,我们需要理解Koin下面的几个组成部分:

  • Koin:Koin框架的使用入口,Koin自身核心功能的实现处
  • Definition:定义,指的是我们写在dsl里面的对象关系、创建规则的相关定义
  • Scope:对象生命周期的管理者
  • Factory:创建对象的工厂,包括了多种方式,例如单例、每次生成新对象、生命周期内内生成唯一对象
  • inject:注入对象,获取注入的对象

这些不同的组成部分我绘制成一个示意图,可以在一段时间后快速帮助自己回忆起Koin的组成部分。(讲道理一段时间后还能让使用者记住他是"如何使用,每个模块的分工以及如何串起来"的依赖注入框架,我还没遇到过)

使用

使用 startKoin 进行初始化:

kotlin 复制代码
// in Application
startKoin {

}

闭包里面可以指定modules的定义,定义modules的时候还可以定义scope、factory:

kotlin 复制代码
modules {
    scope(named("myscope")) {
        scoped {
            // 对象创建
            ...
        }
        factory {
            // 对象创建,每次新创建一个,但是可以随着scope销毁
        }
    }
    factory {
        // 对象创建,每次新创建一个
        ...
    }
}

然后我们在需要使用对象的地方去声明对象并注入对象:

kotlin 复制代码
val obj by inject()
val objWithScope by getKoin().getOrCreatedScope("",named("")).inject()

当对象依赖其他对象的时候,也可以通过get()去获取他的依赖性:

kotlin 复制代码
class Demo(val tag:String){}

// 参数调用get()
factory {
    Demo(get()) // inject内部也调用的是get()
}

原理分析

为了更清晰的理解Koin的运作方式,我们大概来看下他几个关键模块的实现

初始化

startKoin的时候,GlobalContext会创建并初始化我们的KoinApplication对象,KoinApplication是实际的工作对象Koin的包装,负责初始化Koin对象、加载modules等。

加载modules

最终会调用 Koin 的 loadModules 方法: 这里最重要的就是两件事:

  • InstanceRegistry加载Module
  • ScopeRegistry加载Scope

loadModule

loadModule就是把给存放InstanceFactory的Map从Module读取到到InstanceRegistry里面: 那么Module里面的mapping是如何生成的呢?往回追溯,是我们在factory、scoped等方法的时候确定的,他们会通过indexPrimaryType去往mapping写入内容: mapping的key其实就是一个字符串索引,这个索引通过InstanceFactory的type+索引名+scope索引名来确定喂一性。 factory: scoped:

loadScopes

这个比loadModules更简单,就是把Module里面声明的scope读出来,存到ScopeRegistry里面去,这里也能看出来 InstanceRegistry和ScopeRegistry符合单一职责原则,各管各的。

到这一步,对于Koin对象来说,我声明的对象依赖和生命周期都被你读取过去了,那通过Koin帮我创建对象也就不是什么难事了。

inject-创建对象

当我们用 getinject 去注入对象的时候,Koin会根据module+scope的信息帮我们创建我们需要的对象。 inject、get在内部也都是调用的get: 七七八八经过几部调用,会调用InstanceRegistry的resolveInstance: 这时候就会从 _instances 里面取出相对于的 InstanceFactory 去创建对象: 至于这个内层的get方法,其实是Scope对象的方法。所以会结合特定的域的生命周期去创建对象。那外层直接调用 inject 的时候是调用的哪个 Scope 对象呢,那当然是 rootScope 的了,ScopeRegistry默认提供的一个Scope: 而InstanceFactory从最前面的模块图可以看出来,他有3个子类:

  • SingleInstanceFactory: 创建的是单例
  • ScopedInstanceFactory: 根据域创建,同一个域复用对象
  • FactoryInstanceFactory:创建行为和父类默认一直,每次都创建新对象

总结

看到这里相信Koin你也基本掌握基础用法了。Koin的用法还不止这些基础用法,包括Jetpack组件注入的封装,包括Kotlin跨平台的支持。总得来看Koin还是有下面一些优势:

  • 简单简洁易用,快速学习,容易上手
  • 轻量,运行时,不影响编译速度,不会像dagger或者hilt一样生成一堆代码
  • 支持和Kotlin跨平台一起使用,潜力无限
相关推荐
inmK111 小时前
蓝奏云官方版不好用?蓝云最后一版实测:轻量化 + 不限速(避更新坑) 蓝云、蓝奏云第三方安卓版、蓝云最后一版、蓝奏云无广告管理工具、安卓网盘轻量化 APP
android·工具·网盘工具
giaoho11 小时前
Android 热点开发的相关api总结
android
咖啡の猫13 小时前
Android开发-常用布局
android·gitee
程序员老刘13 小时前
Google突然“变脸“,2026年要给全球开发者上“紧箍咒“?
android·flutter·客户端
Tans513 小时前
Androidx Lifecycle 源码阅读笔记
android·android jetpack·源码阅读
雨白14 小时前
实现双向滑动的 ScalableImageView(下)
android
峥嵘life14 小时前
Android Studio新版本编译release版本apk实现
android·ide·android studio
studyForMokey16 小时前
【Android 消息机制】Handler
android
敲代码的鱼哇16 小时前
跳转原生系统设置插件 支持安卓/iOS/鸿蒙UTS组件
android·ios·harmonyos
翻滚丷大头鱼16 小时前
android View详解—动画
android