koin2在android中使用及源码分析

3,026 阅读9分钟

什么是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)其实只是全局注入的ContextApplication单例

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是单例。

注意:相同作用域下factorysingle限定符都不能相同

scope

申明一个作用域,前面的factorysingle方法都是在限定符为“-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方法,在当前作用域下的工厂模式,每次获取都会创建。

当申明作用域的限定名相同时,将合并两个作用域,并且合并的两个作用域scopedfactory不能相同。

    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作用域下scopedfactory限定符都不能相同。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)
                    )
                }
    }

InstanceRegistrycreateEagerInstances方法,主要作用是遍历当前作用域的实例工厂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表达式构造方法创建实例返回。

新手博客语言组织有点不流畅,有啥错误,欢迎指正。