首页 Android 正文
  • 本文约1989字,阅读需10分钟
  • 85
  • 0

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

摘要

总览 koin框架是一个纯Kotlin实现,使用Kotlin DSL去描述对象注入和对象间依赖关系以及创建规则。站在使用方的角度,我们需要理解Koin下面的几个组成部分: Koin:Koin框架的使用入口,Koin自身核心功能的实现处Definition:定义,指的是我们写在dsl里面的对象关系、创建规则的相关定义Scope:对象生命周期的管理者Factor...

总览

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

Koin:Koin框架的使用入口,Koin自身核心功能的实现处Definition:定义,指的是我们写在dsl里面的对象关系、创建规则的相关定义Scope:对象生命周期的管理者Factory:创建对象的工厂,包括了多种方式,例如单例、每次生成新对象、生命周期内内生成唯一对象inject:注入对象,获取注入的对象
这些不同的组成部分我绘制成一个示意图,可以在一段时间后快速帮助自己回忆起Koin的组成部分。(讲道理一段时间后还能让使用者记住他是“如何使用,每个模块的分工以及如何串起来”的依赖注入框架,我还没遇到过)
探索Koin框架:简单、灵活的依赖注入解决方案

使用

使用 startKoin 进行初始化:

startKoin {

}

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

    scope(named("myscope")) {

        scoped {

            // 对象创建

            ...

        }

        factory {

            // 对象创建,每次新创建一个,但是可以随着scope销毁

        }

    }

    factory {

        // 对象创建,每次新创建一个

        ...

    }

}

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

val objWithScope by getKoin().getOrCreatedScope("",named("")).inject()

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

// 参数调用get()

factory {

    Demo(get()) // inject内部也调用的是get()

}

原理分析

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

初始化

探索Koin框架:简单、灵活的依赖注入解决方案
startKoin的时候,GlobalContext会创建并初始化我们的KoinApplication对象,KoinApplication是实际的工作对象Koin的包装,负责初始化Koin对象、加载modules等。
探索Koin框架:简单、灵活的依赖注入解决方案

加载modules

最终会调用 Koin 的 loadModules 方法:
探索Koin框架:简单、灵活的依赖注入解决方案
这里最重要的就是两件事:

  • InstanceRegistry加载Module
  • ScopeRegistry加载Scope

loadModule

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

loadScopes

这个比loadModules更简单,就是把Module里面声明的scope读出来,存到ScopeRegistry里面去,这里也能看出来 InstanceRegistry和ScopeRegistry符合单一职责原则,各管各的。
探索Koin框架:简单、灵活的依赖注入解决方案

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

inject-创建对象

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

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

总结

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

简单简洁易用,快速学习,容易上手轻量,运行时,不影响编译速度,不会像dagger或者hilt一样生成一堆代码支持和Kotlin跨平台一起使用,潜力无限

标签:koin

扫描二维码,在手机上阅读


    评论