什么是koin
官方介绍为:
适用于Kotlin开发人员的实用的轻量级依赖注入框架。仅使用功能解析以纯Kotlin编写:无代理,无代码生成,无反射!
Android配置
//koin android
implementation 'org.koin:koin-android:2.1.0'
// Koin AndroidX Scope功能
implementation 'org.koin:koin-androidx-scope:2.1.0'
// Koin AndroidX ViewModel功能
implementation 'org.koin:koin-androidx-viewmodel:2.1.0'
开始
class MyApplication : Application() {
override fun onCreate() {
super.onCreate()
startKoin {
//使用Koin Android Logger
androidLogger(Level.DEBUG)
//声明Android上下文
androidContext(this@MyApplication)
//声明要使用的模块
modules(myAppModules)
}
}
}
注意:startKoin只能执行一次,如果多次执行会抛出"A KoinContext is already started
single
全局作用域下单例模式,默认懒加载,一旦创建整个koin生命周期内都存在。
single方法
inline fun <reified T> single(
//限定符 用于在保存在对象构造方法map中的key值。为空时为类名,不为空时为",qualifier:$qualifier"
qualifier: Qualifier? = null,
//是否koin一启动就实例对象
createdAtStart: Boolean = false,
//是否覆盖
override: Boolean = false,
// Scope的匿名扩展函数 原形为Scope.(DefinitionParameters) -> T
//主要作用为提供当前注入类的构造方法并且解构参数
noinline definition: Definition<T>
): BeanDefinition<T>
参数定义DefinitionParameters类
class DefinitionParameters internal constructor(vararg val values: Any?) {
private fun <T> elementAt(i: Int): T =
if (values.size > i) values[i] as T else throw NoParameterFoundException("Can't get parameter value #$i from $this")
//重载解构方法
operator fun <T> component1(): T = elementAt(0)
operator fun <T> component2(): T = elementAt(1)
operator fun <T> component3(): T = elementAt(2)
operator fun <T> component4(): T = elementAt(3)
operator fun <T> component5(): T = elementAt(4)
...
}
注入
data class LoginBean(
var phone: String,
var passWord: String,
var user: User
)
class User() {
var name = ""
constructor(s: String) : this() {
name = s
}
}
val myAppModules = module {
//默认在限定符为“-Root-”的root作用域
//注入无参数单例
single { User() }
//在相同作用域下注入相同类型并且都没设置限定符会报覆盖错误
//single { User() }
//single { User() }
//使用覆盖放式注入
single(override = true) { User() }
//相同类型注入使用限定符
single(named("a")) { User() }
single(named("b")) { User() }
//注入多个参数,并且需要引用已注入的单例时 用get()获取
//DefinitionParameters类解构为多个参数
single { (phone: String, passWord: String) ->
LoginBean(phone, passWord, get())
}
}
多module会合并,并且作用域相同
val myAppModules = module {
single { User() }
single(named("a")) { User() }
}
//效果和下面相同
val myAppModules1 = module {
single { User() }
}
val myAppModules2 = module {
single(named("a")) { User() }
}
注意:single方法默认已当前类名为限定名。相同作用域下single限定符不能相同,若非要相同只能通过override = true覆盖操作
startKoin中声明Android上下文androidContext(this@MyApplication)其实只是全局注入的Context和Application单例
fun KoinApplication.androidContext(androidContext: Context): KoinApplication {
if (koin._logger.isAt(Level.INFO)) {
koin._logger.info("[init] declare Android Context")
}
if (androidContext is Application) {
koin.loadModules(listOf(module {
//注入Application
single<Application> { androidContext }
}))
}
koin.loadModules(listOf(module {
//注入Context
single { androidContext }
}))
return this
}
获取
当我们在Activity或者Fragment中使用
class MainActivity : AppCompatActivity() {
//获取默认类
val user:User = get() //直接获取
//val user:User by inject() 懒加载获取
//获取限定符a注入的类
val usera:User = get(named("a"))
//val user:User by inject(named("a")) 懒加载获取
//获取限定符b注入的类
val userb:User = get(named("b"))
//val user:User by inject(named("b")) 懒加载获取
//懒加载获取
val loginBean:LoginBean by inject {
//传参 注意参数要一一对应
parametersOf("189****11","*****")
}
// 直接获取
// val loginBean:LoginBean=get {
// //传参 注意参数要一一对应
// parametersOf("189****11","*****")
// }
}
当我们其他类中使用时需要实现KoinComponent接口或者直接KoinContextHandler类获取
//实现接口获取
class TestBean : KoinComponent {
val user:User = get()
}
//直接KoinContextHandler获取
class TestBean {
val user: User = KoinContextHandler.get().get()
}
KoinComponent接口,其实也是通过KoinContextHandler获取的
//KoinComponent源码
interface KoinComponent {
fun getKoin(): Koin = KoinContextHandler.get()
}
factory
当前作用域下工厂模式,每次获取都会创建一个新的实例 factory方法源码
inline fun <reified T> factory(
//限定符
qualifier: Qualifier? = null,
//是否覆盖
override: Boolean = false,
//提供注入构造方法
noinline definition: Definition<T>
): BeanDefinition<T>
factory方法和single用法相同,唯一区别就是factory每次都会创建新的实例而single是单例。
注意:相同作用域下factory和single限定符都不能相同
scope
申明一个作用域,前面的factory和single方法都是在限定符为“-Root-”的root作用域下
当作用域销毁时,在当前作用域下创建的类都将被释放删除。
scope方法源码
fun scope(qualifier: Qualifier, scopeSet: ScopeDSL.() -> Unit)
//已类名为限定符创建作用域
inline fun <reified T> scope(scopeSet: ScopeDSL.() -> Unit)
注入
申明作用域
val myAppModules = module {
//以类名为限定符申明作用域
scope<User> {
//当前作用域下单例用法和single相同
//scoped和factory在相同作用域下不能同作用域
scoped{User()}
factory(named("factory")){User()}
}
//以"a"为限定符创建
scope(named("a")) {
scoped{User()}
factory(named("factory")){User()}
}
}
scoped方法和single相似,scoped表示在当前申明的作用域下创建单例,生命跟随当前作用域。
factory方法,在当前作用域下的工厂模式,每次获取都会创建。
当申明作用域的限定名相同时,将合并两个作用域,并且合并的两个作用域scoped和factory不能相同。
val myAppModules = module {
//限定符相同
scope(named("a")) {
scoped{User()}
}
scope(named("a")) {
factory(named("factory")){User()}
}
}
...
两者效果相同
val myAppModules = module {
//限定符相同
scope(named("a")) {
scoped{User()}
factory(named("factory")){User()}
}
}
注意:scoped作用域下scoped和factory限定符都不能相同。scope下不能使用single,single只能在root作用域下使用不然会报错误:
"Scoped definition is deprecated and has been replaced with Single scope definitions"
使用
在Activity或者Fragment中使用
class MainActivity : AppCompatActivity() {
//创建scope以User类名为限定名的作用域 作用域id为scopeId1
val scope1 = getKoin().createScope<User>("scopeId1")
//创建scope以a为限定名的作用域 作用域id为scopeId2
val scope2 = getKoin().createScope("scopeId2", named("a"))
//获取scope<User>中注入的类
//直接获取
val scopedUser1:User=scope1.get()
val factoryUser1:User=scope1.get(named("factory"))
//获取scope(named("a"))中注入的类
//懒加载获取
val scopedUser2:User by scope2.inject()
val factoryUser2:User by scope2.inject(named("factory"))
init {
//在Activity或者Fragment中可通过将作用域绑定到当前组件的生命周期中
//当Activity或者Fragment生命结束知道销毁作用域并释放删除当局作用域下生成的类
//手动控制可使用 scope1.close()方法
bindScope(scope1)
bindScope(scope2)
}
}
注意:创建作用域id不能和以创建还未关闭的作用域id相同
koin在Activity或者Fragment中还提供了lifecycleScope来绑定作用域
val myAppModules = module {
//以MainActivity类名来做限定符
scope<MainActivity> {
scoped{User()}
}
}
...
class MainActivity : AppCompatActivity() {
//lifecycleScope获取
val user:User by lifecycleScope.inject()
}
lifecycleScope其实也是创建了以当前类名为限定符,以为类名加"@"加当前类的哈希值为scopeId的作用域,并且绑定到当前生命周期上。
如果在其他类中使用,只需要实现KoinComponent接口或者将getKoin()换成KoinContextHandler.get()就行,注意记得关闭作用域。
viewModel
在Android MVVM框架中使用viewModel时,可以使用viewModel来注入并绑定到当前生命周期中
class MainRepository {
}
class MainActivityViewModel(val repository: MainRepository,val string: String): ViewModel() {
}
class MyApplication : Application() {
override fun onCreate() {
super.onCreate()
startKoin {
//使用Koin Android Logger
androidLogger(Level.DEBUG)
//声明Android上下文
androidContext(this@MyApplication)
//声明要使用的模块
modules(myAppModules)
}
}
val myAppModules = module {
//工厂模式注入
factory { MainRepository() }
//默认类名为限定符 注入ViewModel
viewModel { (string: String) -> MainActivityViewModel(get(), string) }
}
}
//在Activity中获取
class MainActivity : AppCompatActivity() {
//懒加载获取
val viewModels: MainActivityViewModel by viewModel{
parametersOf("参数")
}
//直接获取
//var viewModels:MainActivityViewModel = getViewModel{
// parametersOf("参数")
// }
}
//使用sharedViewModel在Fragment中共享
class MyFragment : Fragment() {
//懒加载获取
val viewModels: MainActivityViewModel by sharedViewModel {
parametersOf("参数")
}
//直接获取
//var viewModels:MainActivityViewModel = getSharedViewModel{
// parametersOf("参数")
// }
}
viewModel源码
inline fun <reified T : ViewModel> Module.viewModel(
//限定符
qualifier: Qualifier? = null,
override: Boolean = false,
noinline definition: Definition<T>
): BeanDefinition<T> {
//使用工厂模式注入
val beanDefinition = factory(qualifier, override, definition)
//设置属性标注isViewModel为true
beanDefinition.setIsViewModel()
return beanDefinition
}
通过源码viewModel注入和factory注入用法相同只是多了个标志isViewModel。
activity获取注入的viewModle时会调用LifecycleOwner.getViewModel()方法,LifecycleOwner.getViewModel()方法经过调用最后会调用Scope的getViewModel方法。
fun <T : ViewModel> Scope.getViewModel(viewModelParameters: ViewModelParameter<T>): T {
//创建viewModelProvider
val viewModelProvider = createViewModelProvider(viewModelParameters)
//调用viewModelProvider.get方法获取viewModel
return viewModelProvider.resolveInstance(viewModelParameters)
}
internal fun <T : ViewModel> Scope.createViewModelProvider(
viewModelParameters: ViewModelParameter<T>
): ViewModelProvider {
return ViewModelProvider(
//当前activity或Fragment的viewModelStore
viewModelParameters.viewModelStore,
if (viewModelParameters.bundle != null) {
stateViewModelFactory(viewModelParameters)
} else {
defaultViewModelFactory(viewModelParameters)
}
)
}
fun <T : ViewModel> Scope.defaultViewModelFactory(parameters: ViewModelParameter<T>): ViewModelProvider.Factory {
return object : ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
//Scope的get方法获取注入类 当前Scope为rootScope(默认`factory`和`single`注入root作用域 )
//Scope中的InstanceRegistry类,通过map键值对存储注入的类(限定符为键,构造工厂为值)
return get(
//类型
parameters.clazz,
//限定符
parameters.qualifier,
//参数
parameters.parameters
)
}
}
}
大致流程就是通过koin自己封装实现ViewModelProvider.Factory方法,在ViewModelProvider.Factory方法中获取注入的类。
koin源码分析
首先认识koin主要的类:
主要类
Koin
核心类,启动koin时会在GlobalContext下创建实例,里面主要保存了作用域注册表_scopeRegistry。
class Koin {
val _scopeRegistry = ScopeRegistry(this)
..
}
ScopeRegistry
作用域注册表ScopeRegistry,里面保存了注入的作用域申明HashMap和创建的作用域实例HashMap。
class ScopeRegistry(private val _koin: Koin) {
private val _scopeDefinitions = HashMap<QualifierValue, ScopeDefinition>()
//作用域申明Map 键为作用域限定符
val scopeDefinitions: Map<QualifierValue, ScopeDefinition>
get() = _scopeDefinitions
//作用域实例Map 键为作用域id
private val _scopes = HashMap<ScopeID, Scope>()
val scopes: Map<ScopeID, Scope>
get() = _scopes
//root作用域申明
var _rootScopeDefinition: ScopeDefinition? = null
var _rootScope: Scope? = null
//root作用域实例
val rootScope: Scope
get() = _rootScope ?: error("No root scoped initialized")
...
}
ScopeDefinition
作用域申明类,申明一个作用域并保存了当前作用域下注入的封装类
class ScopeDefinition(val qualifier: Qualifier, val isRoot: Boolean = false, private val _definitions: HashSet<BeanDefinition<*>> = hashSetOf()) {
//保存注入类的封装类
val definitions: Set<BeanDefinition<*>>
get() = _definitions
...
}
BeanDefinition
封装类,主要用于封装注入类,里面保存了注入类的构造lambda表达式,参数,限定符及申明在哪个作用域下等属性。
data class BeanDefinition<T>(
//当前注入类所在的作用域
val scopeDefinition: ScopeDefinition,
//类型
val primaryType: KClass<*>,
//注入类限定符 默认为类名 否者为",qualifier:$qualifier"
val qualifier: Qualifier? = null,
//注入类的构造lambda表达式
val definition: Definition<T>,
//类型Single, Factory
val kind: Kind,
val secondaryTypes: List<KClass<*>> = listOf(),
//选项options 是否覆盖或者一启动就创建
val options: Options = Options(),
//注入类 自定义属性里面为map表
val properties: Properties = Properties(),
val callbacks: Callbacks<T> = Callbacks()
)
Scope
作用域实例,表示一个作用域申明的具体实现。主要引用实例注册类InstanceRegistry
data class Scope(
val id: ScopeID,
val _scopeDefinition: ScopeDefinition,
val _koin: Koin
) {
...
val _instanceRegistry = InstanceRegistry(_koin, this)
...
}
InstanceRegistry
实例注册类InstanceRegistry中保存了当前作用域下所有注入类实例工厂。
class InstanceRegistry(val _koin: Koin, val _scope: Scope) {
//保存当前作用域实例中,所有注入类的工厂,键为注入类的限定符
private val _instances = HashMap<IndexKey, InstanceFactory<*>>()
val instances: Map<IndexKey, InstanceFactory<*>>
get() = _instances
...
}
InstanceFactory
虚拟类实例工厂类,主要作用为调用注入类的构造lambda表达式,生成具体实例。
InstanceFactory类的默认创建类方法
open fun create(context: InstanceContext): T {
if (_koin._logger.isAt(Level.DEBUG)) {
_koin._logger.debug("| create instance for $beanDefinition")
}
try {
//获取传入的构造参数
val parameters: DefinitionParameters = context.parameters
//调用注入类封装对象的构造lambda表达式 创建一个实例
return beanDefinition.definition.invoke(
context.scope,
parameters
)
} catch (e: Exception) {
val stack =
e.toString() + ERROR_SEPARATOR + e.stackTrace.takeWhile { !it.className.contains("sun.reflect") }
.joinToString(ERROR_SEPARATOR)
_koin._logger.error("Instance creation error : could not create instance for $beanDefinition: $stack")
throw InstanceCreationException("Could not create instance for $beanDefinition", e)
}
}
Module
注入模块类,主要保存当前注入类的封装对象和所在的作用域申明。
class Module(
//当前模块是否一加载就创建模块下的实例
val createAtStart: Boolean,
//是否覆盖
val override: Boolean
) {
//默认在root作用域申明下
val rootScope: ScopeDefinition = ScopeDefinition.rootDefinition()
//是否已经加载过
var isLoaded: Boolean = false
internal set
//通过scop自定义申明的作用域
val otherScopes = arrayListOf<ScopeDefinition>()
...
}
类关系图如下
分析
startKoin启动koin
fun startKoin(koinContext: KoinContext = GlobalContext(), appDeclaration: KoinAppDeclaration): KoinApplication {
//全局单例KoinContextHandler中的_context赋值为KoinContext
KoinContextHandler.register(koinContext)
//创建一个KoinApplication并初始化 KoinApplication中创建了koin() 并且初始化了koin中的root作用域定义_rootScopeDefinition
val koinApplication = KoinApplication.init()
//赋值koinContext中_koin为koinApplication.koin
KoinContextHandler.start(koinApplication)
//appDeclaration为 KoinApplication.() -> Unit 及执行传入的lambda表达式
appDeclaration(koinApplication)
//创建
koinApplication.createEagerInstances()
return koinApplication
}
KoinApplication.init()方法,调用koin作用域表创建一个root作用域申明
KoinApplication->init
internal fun init() {
koin._scopeRegistry.createRootScopeDefinition()
}
调用作用域注册表的createRootScopeDefinition方法创建root作用域申明
class ScopeRegistry(private val _koin: Koin) {
...
private val _scopeDefinitions = HashMap<QualifierValue, ScopeDefinition>()
...
var _rootScopeDefinition: ScopeDefinition? = null
...
internal fun createRootScopeDefinition() {
//创建一个作用域限定符为"-Root-" isRoot为true的作用域申明
val scopeDefinition = ScopeDefinition.rootDefinition()
//添加root作用域申明 添加到作用域申明map中 键为限定符"-Root-"
_scopeDefinitions[ScopeDefinition.ROOT_SCOPE_QUALIFIER.value] =
scopeDefinition
//赋值root作用域申明
_rootScopeDefinition = scopeDefinition
}
...
}
整个KoinApplication.init()方法就执行完成了,初始化作用域注册表中的root作用域。接着就是执行我们传入的KoinApplication.() -> Unit lambda表达式。
startKoin {
//使用Koin Android Logger
androidLogger(Level.DEBUG)
//声明Android上下文
androidContext(this@MyApplication)
//声明要使用的模块
modules(myAppModules)
}
val myAppModules = module {
//类名为注入类限定符
single { User() }
scope(named("自定义作用域申明")) {
scoped(named("注入类限定符")) { User() }
}
}
模块生成
首先我们先看定义模块module类
typealias ModuleDeclaration = Module.() -> Unit
fun module(createdAtStart: Boolean = false, override: Boolean = false, moduleDeclaration: ModuleDeclaration): Module {
//创建一个模块Module类
val module = Module(createdAtStart, override)
//执行传入的匿名扩展函数
moduleDeclaration(module)
return module
}
所以将执行我们注入的类
val myAppModules = module {
//类名为注入类限定符
single { User() }
scope(named("自定义作用域申明")) {
scoped(named("注入类限定符")) { User() }
}
}
single { User() }注入单例User类,先看single方法定义
class Module(
val createAtStart: Boolean,
val override: Boolean
) {
//调用ScopeDefinition中的伴生对象创建限定符为"-Root-" isRoot = true的作用域申明对象
val rootScope: ScopeDefinition = ScopeDefinition.rootDefinition()
var isLoaded: Boolean = false
internal set
//当前模块下自定义的作用域申明列表
val otherScopes = arrayListOf<ScopeDefinition>()
...
inline fun <reified T> single(
qualifier: Qualifier? = null,
createdAtStart: Boolean = false,
override: Boolean = false,
noinline definition: Definition<T>
): BeanDefinition<T> {
//保存单例并返回封装类
return Definitions.saveSingle(
qualifier,
definition,
//注入在root作用域申明中
rootScope,
makeOptions(override, createdAtStart)
)
}
...
}
Definitions.saveSingle方法主要为保存单例并返回封装类
<!--Definitions-->
inline fun <reified T> saveSingle(
qualifier: Qualifier? = null,
noinline definition: Definition<T>,
scopeDefinition: ScopeDefinition,
options: Options
): BeanDefinition<T> {
//将注入单例封装为BeanDefinition对象
val beanDefinition = createSingle(qualifier, definition, scopeDefinition, options)
//在当前作用域中保存注入的封装对象
scopeDefinition.save(beanDefinition)
return beanDefinition
}
inline fun <reified T> createSingle(
qualifier: Qualifier? = null,
noinline definition: Definition<T>,
scopeDefinition: ScopeDefinition,
options: Options,
secondaryTypes: List<KClass<*>> = emptyList()
): BeanDefinition<T> {
//将注入单例封装为BeanDefinition对象
return BeanDefinition(
scopeDefinition,
T::class,
qualifier,
definition,
//类型为单例
Kind.Single,
options = options,
secondaryTypes = secondaryTypes
)
}
scopeDefinition.save(beanDefinition)方法
class ScopeDefinition(val qualifier: Qualifier, val isRoot: Boolean = false, private val _definitions: HashSet<BeanDefinition<*>> = hashSetOf()) {
val definitions: Set<BeanDefinition<*>>
get() = _definitions
//把注入类 保存到当前所在的作用域申明中
fun save(beanDefinition: BeanDefinition<*>, forceOverride: Boolean = false) {
if (definitions.contains(beanDefinition)) {
if (beanDefinition.options.override || forceOverride) {
_definitions.remove(beanDefinition)
} else {
val current = definitions.firstOrNull { it == beanDefinition }
throw DefinitionOverrideException("Definition '$beanDefinition' try to override existing definition. Please use override option or check for definition '$current'")
}
}
_definitions.add(beanDefinition)
}
}
module {single { User()}整体流程为,先创建一个Module类,Module类中会创建一个限定符为"-Root-" isRoot = true的作用域申明对象和一个其他作用域列表。single方法会把注入的类封装成BeanDefinition对象,并保存到root作用域申明类的definitions中。
而当执行scope(named("自定义作用域申明")) {scoped(named("注入类限定符")) { User() }时会先创建一个作用域申明类ScopeDefinition,然后加入到Module类的val otherScopes = arrayListOf<ScopeDefinition>()列表中,所以整个
模块的执行流程图大致为:
加载模块
接着就执行重要的加载模块的modules(myAppModules)方法,把我们定义的模块加载到koin容器中。
首先我们传入的模块会被封装为List然后执行modules方法,modules源码为
<!--KoinApplication-->
fun modules(modules: List<Module>): KoinApplication {
if (koin._logger.isAt(Level.INFO)) {
val duration = measureDuration {
loadModules(modules)
}
val count = koin._scopeRegistry.size()
koin._logger.info("loaded $count definitions - $duration ms")
} else {
//执行加载模块 将会执行koin.loadModules(modules)
loadModules(modules)
}
if (koin._logger.isAt(Level.INFO)) {
val duration = measureDuration {
koin.createRootScope()
}
koin._logger.info("create context - $duration ms")
} else {
//创建root作用域
koin.createRootScope()
}
return this
}
KoinApplication加载模块 将会执行koin.loadModules(modules),所以我们查看koin的加载模块方法
class Koin {
val _scopeRegistry = ScopeRegistry(this)
...
val _modules = hashSetOf<Module>()
...
fun loadModules(modules: List<Module>) = synchronized(this) {
//保存加载的模块
_modules.addAll(modules)
//执行作用域注册表中的加载模块
_scopeRegistry.loadModules(modules)
}
...
}
koin中会先把需要加载的模块保存起来,然后调用作用域注册表的加载方法,继续查看注册表中的加载方法
<!--ScopeRegistry-->
internal fun loadModules(modules: Iterable<Module>) {
modules.forEach { module ->
if (!module.isLoaded) {
//调用加载
loadModule(module)mo
module.isLoaded = true
} else {
_koin._logger.error("module '$module' already loaded!")
}
}
}
作用域注册表会遍历模块,如果没加载就继续调用loadModule(module)加载方法,并将isLoaded设置为true。如果当前模块已经加载,则抛出异常。查看源码
<!--ScopeRegistry-->
private fun loadModule(module: Module) {
//加载module中root作用域申明
declareScope(module.rootScope)
//加载module中其他作用域申明
declareScopes(module.otherScopes)
}
declareScope方法又会调用declareDefinitions方法,declareDefinitions方法最终才会加载模块,declareDefinitions方法
<!--ScopeRegistry-->
//ScopeRegistry中的作用域map
val scopeDefinitions: Map<QualifierValue, ScopeDefinition>
//加载模块的核心方法
private fun declareDefinitions(definition: ScopeDefinition) {
//如果当前作用域申明map中已经了当前注入作用域的限定符
if (scopeDefinitions.contains(definition.qualifier.value)) {
mergeDefinitions(definition)
} else {
//保存注入的作用域申明
_scopeDefinitions[definition.qualifier.value] = definition.copy()
}
}
//合并 如果作用域map(scopeDefinitions)中已经有了注入模块作用域申明的限定符,
//那么就把模块中作用域申明保存的封装对象添加到map中相同限定符作用域申明中
private fun mergeDefinitions(definition: ScopeDefinition) {
val existing = scopeDefinitions[definition.qualifier.value]
?: error("Scope definition '$definition' not found in $_scopeDefinitions")
definition.definitions.forEach {
existing.save(it)
}
}
加载模块,最终只是把模块中作用域申明保存到了koin中ScopeRegistry的作用域map。当加载完模块后还执行了koin的创建root作用域方法koin.createRootScope(),最终也会执行作用域注册表ScopeRegistry的创建root作用域方法
<!--ScopeRegistry-->
internal fun createRootScope() {
if (_rootScope == null) {
_rootScope =
createScope(ScopeDefinition.ROOT_SCOPE_ID, ScopeDefinition.ROOT_SCOPE_QUALIFIER)
}
}
createRootScope方法大致流程为创建限定符为"-Root-"的作用域,并在ScopeRegistry的val scopes: Map<ScopeID, Scope>保存起来。整个加载模块流程就基本完成了。大致流程图为:
createRootScope的详细流程。createRootScope会调用createScope方法
<!--ScopeRegistry-->
val scopeDefinitions: Map<QualifierValue, ScopeDefinition>
...
private val _scopes = HashMap<ScopeID, Scope>()
//首先调用 参数作用域id和限定符
fun createScope(scopeId: ScopeID, qualifier: Qualifier): Scope {
//判断当前作用域map中是否已经创建了当前作用域id
if (scopes.contains(scopeId)) {
throw ScopeAlreadyCreatedException("Scope with id '$scopeId' is already created")
}
//获取作用域定义中是否申明了当前限定符的作用域 (前面加载loadModule(module)方法已经赋值)
val scopeDefinition = scopeDefinitions[qualifier.value]
return if (scopeDefinition != null) {
//创建当前作用域
val createdScope: Scope = createScope(scopeId, scopeDefinition)
_scopes[scopeId] = createdScope
createdScope
} else {
throw NoScopeDefFoundException("No Scope Definition found for qualifer '${qualifier.value}'")
}
}
//参数为 作用域id和作用域申明
private fun createScope(scopeId: ScopeID, scopeDefinition: ScopeDefinition): Scope {
//创建作用域
val scope = Scope(scopeId, scopeDefinition, _koin)
//判断根作用域是否存在(当前加载模块步骤中还为赋值,执行完成后才了赋值)
val links = _rootScope?.let { listOf(it) } ?: emptyList()
//作用域创建初始化
scope.create(links)
return scope
}
createRootScope方法的大致流程为,首先判断当前作用域map中是否已经存在当前的scopeId的作用域实例,如果不存在就获取当前作用域定义map中是否
存在当前限定符的作用域申明。如果存在作用域申明,就以当前作用域申明为参数构建作用域Scope的实例。然后执scope.create(links)方法创建初始化。查看源码:
data class Scope(
val id: ScopeID,
val _scopeDefinition: ScopeDefinition,
val _koin: Koin
) {
val _linkedScope: ArrayList<Scope> = arrayListOf()
val _instanceRegistry = InstanceRegistry(_koin, this)
...
internal fun create(links: List<Scope>) {
//调用实例注册的创建方法
_instanceRegistry.create(_scopeDefinition.definitions)
_linkedScope.addAll(links)
}
}
scope.create(links)只是简单的调用了实例注册的创建方法。
<!--InstanceRegistry-->
private val _instances = HashMap<IndexKey, InstanceFactory<*>>()
internal fun create(definitions: Set<BeanDefinition<*>>) {
//遍历当前作用域申明中保存的所以注入类封装对象
definitions.forEach { definition ->
...
//保存作用域申明
saveDefinition(definition, override = false)
}
}
fun saveDefinition(definition: BeanDefinition<*>, override: Boolean) {
val defOverride = definition.options.override || override
//以注入类的封装对象BeanDefinition创建实例工厂,里面可通过注入类的构造方法创建实例
val instanceFactory = createInstanceFactory(_koin, definition)
//保存到实例工厂map
saveInstance(
indexKey(definition.primaryType, definition.qualifier),
instanceFactory,
defOverride
)
...
}
private fun saveInstance(key: IndexKey, factory: InstanceFactory<*>, override: Boolean) {
if (_instances.contains(key) && !override) {
error("InstanceRegistry already contains index '$key'")
} else {
_instances[key] = factory
}
}
最终scope.create(links)方法会将当前作用域申明中保存的封装类,全部转换为实例工厂map(HashMap<IndexKey, InstanceFactory<*>>())保存Scope类中的InstanceRegistry中。createScope大致流程图为
startKoin方法中的koinApplication.createEagerInstances()创建实例。
创建实例
koinApplication.createEagerInstances()方法主要调用了koinApplication中的koin实例的createEagerInstances方法。所以查看koin中的createEagerInstances方法。
<!--Koin-->
internal fun createEagerInstances() {
createContextIfNeeded()
_scopeRegistry.rootScope.createEagerInstances()
}
internal fun createContextIfNeeded() {
if (_scopeRegistry._rootScope == null) {
//创建根作用域,加载模块时已经创建并赋值
_scopeRegistry.createRootScope()
}
}
createEagerInstances方法很简单,主要是查看根作用域是创建,没创建就创建,然后调用根作用域的createEagerInstances方法
<!--Scope-->
//实例注册类 保存了当前作用域下所有注入类实例工厂
val _instanceRegistry = InstanceRegistry(_koin, this)
...
internal fun createEagerInstances() {
//如果是根作用域
if (_scopeDefinition.isRoot) {
_instanceRegistry.createEagerInstances()
}
}
Scope中的createEagerInstances方法最后会调用Scope中引用的实例注册类InstanceRegistry的createEagerInstances方法。查看InstanceRegistry的方法
<!--InstanceRegistry-->
//保存实例工厂的map
val instances: Map<IndexKey, InstanceFactory<*>>
...
internal fun createEagerInstances() {
//当前实例工厂map中是否有注入类设置了“createdAtStart”为true的并且为单例模式时 即一开始就创建
instances.values.filterIsInstance<SingleInstanceFactory<*>>()
.filter { instance -> instance.beanDefinition.options.isCreatedAtStart }
.forEach { instance ->
//如果createdAtStart为ture就创建实例
instance.get(
InstanceContext(_koin, _scope)
)
}
}
InstanceRegistry的createEagerInstances方法,主要作用是遍历当前作用域的实例工厂map,如果设置了“createdAtStart”为true就立即创建实例。
<!--SingleInstanceFactory-->
override fun get(context: InstanceContext): T {
//是否已经创建
if (!isCreated()) {
//create会调用父类InstanceFactory.create()方法
value = create(context)
}
return value ?: error("Single instance created couldn't return value")
}
<!--InstanceFactory-->
open fun create(context: InstanceContext): T {
if (_koin._logger.isAt(Level.DEBUG)) {
_koin._logger.debug("| create instance for $beanDefinition")
}
try {
//获取参数
val parameters: DefinitionParameters = context.parameters
//调用注入类封装对象的构造lambda表达式 创建一个实例
return beanDefinition.definition.invoke(
context.scope,
parameters
)
} catch (e: Exception) {
val stack =
e.toString() + ERROR_SEPARATOR + e.stackTrace.takeWhile { !it.className.contains("sun.reflect") }
.joinToString(ERROR_SEPARATOR)
_koin._logger.error("Instance creation error : could not create instance for $beanDefinition: $stack")
throw InstanceCreationException("Could not create instance for $beanDefinition", e)
}
}
整个koinApplication.createEagerInstances()方法主要就是遍历rootScope下的val instances: Map<IndexKey, InstanceFactory<*>>然后把单例注入并且“createdAtStart”为true的实例化。
到此整个startKoin流程基本上启动完成,接下来就是获取注入类了。
获取
在Activity中获取注入类时
//注入的模块
val myAppModules = module {
//类名为注入类限定符
single { User() }
scope(named("自定义作用域申明")) {
scoped(named("注入类限定符")) { User() }
}
class MainActivity : AppCompatActivity() {
//1获取单例
var user1: User = get()
//2获取自定义作用域的注入类
var scope = getKoin().createScope("scopeID", named("自定义作用域申明"))
var user2: User = scope.get(named("注入类限定符"))
}
首先我们看直接获取var user1: User = get()会先获取koin然后会调用koin的get方法
inline fun <reified T> get(
qualifier: Qualifier? = null,
noinline parameters: ParametersDefinition? = null
): T = _scopeRegistry.rootScope.get(qualifier, parameters)//直接调用了koin作用域注册表中根作用域rootScope的get方法
可以看到默认获取都是在rootScope中查询注入的类。
然后我们查看var scope = getKoin().createScope("scopeID", named("自定义作用域申明"))获取自定义作用域。直接调用了koin的createScope方法,koin的createScope方法再调用了ScopeRegistry的createScope(scopeId: ScopeID, qualifier: Qualifier)方法。
<!--ScopeRegistry-->
fun createScope(scopeId: ScopeID, qualifier: Qualifier): Scope {
if (scopes.contains(scopeId)) {
throw ScopeAlreadyCreatedException("Scope with id '$scopeId' is already created")
}
val scopeDefinition = scopeDefinitions[qualifier.value]
return if (scopeDefinition != null) {
val createdScope: Scope = createScope(scopeId, scopeDefinition)
_scopes[scopeId] = createdScope
createdScope
} else {
throw NoScopeDefFoundException("No Scope Definition found for qualifer '${qualifier.value}'")
}
}
createScope(scopeId: ScopeID, qualifier: Qualifier)方法我们前面在执行koinApplication.createEagerInstances()调用过并且创建了rootScope。所以在这里就是创建一个自己申明的作用域,并保持到scopes中。
最后获取单例还是获取在自定义作用域申明中的注入类时,都调用了Scope的get方法。
<!--Scope-->
fun <T> get(
clazz: KClass<*>,
qualifier: Qualifier? = null,
parameters: ParametersDefinition? = null
): T {
...
resolveInstance(qualifier, clazz, parameters)
...
}
get方法会调用resolveInstance解析实例
<!--Scope-->
private fun <T> resolveInstance(
qualifier: Qualifier?,
clazz: KClass<*>,
parameters: ParametersDefinition?
): T {
if (_closed) {
throw ClosedScopeException("Scope '$id' is closed")
}
//当限定符为空获取类名 否者获取限定符
val indexKey = indexKey(clazz, qualifier)
//调用注册实例InstanceRegistry类的解析方法
return _instanceRegistry.resolveInstance(indexKey, parameters)
?: findInOtherScope<T>(clazz, qualifier, parameters)
?: throwDefinitionNotFound(qualifier, clazz)
}
<!--InstanceRegistry-->
internal fun <T> resolveInstance(indexKey: IndexKey, parameters: ParametersDefinition?): T? {
//在保存的_instances中查找当前key的实例工厂并构造实例
return _instances[indexKey]?.get(defaultInstanceContext(parameters)) as? T
}
解析实例就是查找Scope作用域中的实例注册类InstanceRegistry中保存的实例工厂InstanceFactory,然后调用实例工厂InstanceFactory的get方法去创建当前注入的实例,然后返回。到此整个koin获取注入类的流程就完成了。
结语
koin整体用法还是很简单。框架的主要思想就是通过在koin中保存注入类的lambda表达式,然后在获取的时候根据键值对去查找,并通过注入的lambda表达式构造方法创建实例返回。
新手博客语言组织有点不流畅,有啥错误,欢迎指正。