一个依赖注入框架,无非就是注入与获取实例。那么kodein是怎么注入的?
注入
val kodein = Kodein {
bind<Die>() with singleton { Die(instance()) }
bind<Random>() with singleton { Random(instance) }
constant(tag "max") with 5
}
可以看到首先要初始化Kodien
环境,
KodeinImpl
internal open class KodeinImpl internal constructor(private val _container: KodeinContainerImpl) : Kodein {
@Suppress("unused")
private constructor(builder: KodeinMainBuilderImpl, runCallbacks: Boolean) : this(KodeinContainerImpl(builder.containerBuilder, builder.externalSources, builder.fullDescriptionOnError, runCallbacks))
constructor(allowSilentOverride: Boolean = false, init: Kodein.MainBuilder.() -> Unit) : this(newBuilder(allowSilentOverride, init), true)
companion object {
private fun newBuilder(allowSilentOverride: Boolean = false, init: Kodein.MainBuilder.() -> Unit) = KodeinMainBuilderImpl(allowSilentOverride).apply(init)
fun withDelayedCallbacks(allowSilentOverride: Boolean = false, init: Kodein.MainBuilder.() -> Unit): Pair<Kodein, () -> Unit> {
val kodein = KodeinImpl(newBuilder(allowSilentOverride, init), false)
return kodein to { kodein._container.initCallbacks?.invoke() ; Unit }
}
}
final override val container: KodeinContainer by lazy {
if (_container.initCallbacks != null)
throw IllegalStateException("Kodein has not been initialized")
_container
}
}
这里会内部构建好一个Kodien.Builder
,调用初始化函数后,传入一个container
这里KodienBuilder
通过调用bind
返回一个binder
,供上层去绑定一个实例
Binders
所以我们看到builder
其实提供了一个bind
方法,对外暴露接口获取binder。
inner class TypeBinder<T : Any> internal constructor(val type: TypeToken<out T>, val tag: Any?, val overrides: Boolean?) : Kodein.Builder.TypeBinder<T> {
internal val containerBuilder get() = this@KodeinBuilderImpl.containerBuilder
override infix fun <C, A> with(binding: KodeinBinding<in C, in A, out T>) = containerBuilder.bind(Kodein.Key(binding.contextType, binding.argType, type, tag), binding, moduleName, overrides)
}
inner class DirectBinder internal constructor(private val _tag: Any?, private val _overrides: Boolean?) : Kodein.Builder.DirectBinder {
override infix fun <C, A, T: Any> from(binding: KodeinBinding<in C, in A, out T>) {
if (binding.createdType == UnitToken) {
throw IllegalArgumentException("Using `bind() from` with a *Unit* ${binding.factoryName()} is most likely an error. If you are sure you want to bind the Unit type, please use `bind<Unit>() with ${binding.factoryName()}`.")
}
containerBuilder.bind(Kodein.Key(binding.contextType, binding.argType, binding.createdType, _tag), binding, moduleName, _overrides)
}
}
inner class ConstantBinder internal constructor(private val _tag: Any, private val _overrides: Boolean?) : Kodein.Builder.ConstantBinder {
@Suppress("FunctionName")
override fun <T: Any> With(valueType: TypeToken<out T>, value: T) = Bind(tag = _tag, overrides = _overrides) from InstanceBinding(valueType, value)
}
然后我们来看看binder
可以绑定哪些binding
Bindings
/**
* @param C The type of the context used by the retriever.
* @param A The type of argument used to create or retrieve an instance.
* @param T The type of instance this factory creates or retrieves.
*/
interface Binding<C, A, T: Any> {
fun getFactory(kodein: BindingKodein<C>, key: Kodein.Key<C, A, T>): (A) -> T
}
Binding
是什么,就是根据key
返回一个构造器,这个构造器接受一个参数返回一个实例。
Factory
class Factory<C, A, T: Any>(override val contextType: TypeToken<in C>, override val argType: TypeToken<in A>, override val createdType: TypeToken<out T>, private val creator: BindingKodein<C>.(A) -> T) : KodeinBinding<C, A, T> {
override fun factoryName() = "factory"
override fun getFactory(kodein: BindingKodein<C>, key: Kodein.Key<C, A, T>): (A) -> T = { arg -> this.creator(kodein, arg) }
}
Multiton
class Multiton<C, A, T: Any>(override val scope: Scope<C>, override val contextType: TypeToken<in C>, override val argType: TypeToken<in A>, override val createdType: TypeToken<out T>, refMaker: RefMaker? = null, val sync: Boolean = true, private val creator: SimpleBindingKodein<C>.(A) -> T) : KodeinBinding<C, A, T> {
private val _refMaker = refMaker ?: SingletonReference
private val _scopeId = Any()
override fun getFactory(kodein: BindingKodein<C>, key: Kodein.Key<C, A, T>): (A) -> T {
val registry = scope.getRegistry(kodein.context)
return { arg ->
@Suppress("UNCHECKED_CAST")
registry.getOrCreate(ScopeKey(_scopeId, arg), sync) { _refMaker.make { BindingContextedKodein(kodein, kodein.context).creator(arg) } } as T
}
}
override val copier = KodeinBinding.Copier { Multiton(scope, contextType, argType, createdType, _refMaker, sync, creator) }
}
首先通过scope.getRegistry(kodein.context)
拿到registry
,啥意思,拿到一个存储实例的registry
,这里可以和生命周期(context)绑定。
registry.getOrCreate(ScopeKey(_scopeId, arg), sync) { _refMaker.make { BindingContextedKodein(kodein, kodein.context).creator(arg) } } as T
对于scopeKey
(是data class),可以看到如果arg
一样是不会create的,如果不存在的话,通过creator()
函数创建一个
Provider
class Provider<C, T: Any>(override val contextType: TypeToken<in C>, override val createdType: TypeToken<out T>, val creator: NoArgBindingKodein<C>.() -> T) : NoArgKodeinBinding<C, T> {
override fun factoryName() = "provider"
override fun getFactory(kodein: BindingKodein<C>, key: Kodein.Key<C, Unit, T>): (Unit) -> T = { NoArgBindingKodeinWrap(kodein).creator() }
}
Singleton
class Singleton<C, T: Any>(override val scope: Scope<C>, override val contextType: TypeToken<in C>, override val createdType: TypeToken<out T>, refMaker: RefMaker? = null, val sync: Boolean = true, val creator: NoArgSimpleBindingKodein<C>.() -> T) : NoArgKodeinBinding<C, T> {
@Suppress("UNCHECKED_CAST")
private val _refMaker = refMaker ?: SingletonReference
private val _scopeKey = ScopeKey(Any(), Unit)
/**
* @see [KodeinBinding.getFactory]
*/
override fun getFactory(kodein: BindingKodein<C>, key: Kodein.Key<C, Unit, T>): (Unit) -> T {
val registry = scope.getRegistry(kodein.context)
return {
@Suppress("UNCHECKED_CAST")
registry.getOrCreate(_scopeKey, sync) { _refMaker.make { NoArgBindingKodeinWrap(BindingContextedKodein(kodein, kodein.context)).creator() } } as T
}
}
override val copier = KodeinBinding.Copier { Singleton(scope, contextType, createdType, _refMaker, sync, creator) }
}
InstanceBinding
class InstanceBinding<T: Any>(override val createdType: TypeToken<out T>, val instance: T) : NoArgKodeinBinding<Any?, T> {
override fun factoryName() = "instance"
override val contextType = AnyToken
/**
* @see [KodeinBinding.getFactory]
*/
override fun getFactory(kodein: BindingKodein<Any?>, key: Kodein.Key<Any?, Unit, T>): (Unit) -> T = { this.instance }
}
就返回一个已经初始化好的instance
Eager
class EagerSingleton<T: Any>(builder: KodeinContainer.Builder, override val createdType: TypeToken<out T>, val creator: NoArgSimpleBindingKodein<Any?>.() -> T) : NoArgKodeinBinding<Any?, T> {
override val contextType = AnyToken
@Volatile private var _instance: T? = null
private val _lock = Any()
private fun getFactory(kodein: BindingKodein<Any?>): (Unit) -> T {
return { _ ->
synchronizedIfNull(
lock = _lock,
predicate = this@EagerSingleton::_instance,
ifNotNull = { it },
ifNull = {
NoArgBindingKodeinWrap(kodein).creator().also { _instance = it }
}
)
}
}
init {
val key = Kodein.Key(AnyToken, UnitToken, createdType, null)
builder.onReady { getFactory(BindingKodeinImpl(this, key, null, 0)).invoke(Unit) }
}
override val copier = KodeinBinding.Copier { builder -> EagerSingleton(builder, createdType, creator) }
}
builder.onReady
,当kodein容器??
准备好时就通过getFactory
初始化实例
这里我们暂时知道bindings
就是返回一个函数,这个函数传入参数能返回我们需要的实例T。
那么binder
和binding
是怎么结合起来的,就通过一个初始化好的KodeinContainerBuilder
去对bindings
进行配置。
KodeinContainerBuilderImpl
配置bindings
internal class KodeinContainerBuilderImpl(
allowOverride: Boolean,
silentOverride: Boolean,
internal val bindingsMap: MutableMap<Kodein.Key<*, *, *>, MutableList<KodeinDefining<*, *, *>>>,
internal val callbacks: MutableList<DKodein.() -> Unit>,
internal val translators: MutableList<ContextTranslator<*, *>>
)
配置能否override
,持有bindingMap
,
Bind
当开始绑定时,会将绑定关系放入bindingMap
val bindings = bindingsMap.getOrPut(key) { newLinkedList() }
bindings.add(0, KodeinDefining(binding, fromModule))
Extend
配置可以从已有的kodeinContainer
中继承
override fun extend(container: KodeinContainer, allowOverride: Boolean, copy: Set<Kodein.Key<*, *, *>>) {
checkMatch(allowOverride)
container.tree.bindings.forEach { (key, bindings) ->
if (!allowOverride)
checkOverrides(key, null)
val newBindings = if (key in copy) {
newLinkedList<KodeinDefining<*, *, *>>().also {
bindings.mapTo(it) { KodeinDefining(it.binding.copier?.copy(this@KodeinContainerBuilderImpl) ?: it.binding, it.fromModule) }
}
}
else {
newLinkedList<KodeinDefining<*, *, *>>(bindings)
}
bindingsMap[key] = newBindings
}
translators += container.tree.registeredTranslators
}
获取实例
前面bb了这么多,那怎么获取实例呢?
private val viewModel: AlbumListViewModel by instance()
fun <T : Any> KodeinAware.Instance(type: TypeToken<out T>, tag: Any? = null): KodeinProperty<T> =
KodeinProperty(kodeinTrigger, kodeinContext) { ctx, _ -> kodein.container.provider(Kodein.Key(ctx.anyType, UnitToken, type, tag), ctx.value).invoke() }
这里返回一个lazy
属性,
KodeinProperty
kodein
使用lazy
能力。
通过定义 provideDelegate 操作符,可以扩展创建属性实现所委托对象的逻辑:
解释
interface LazyDelegate<out V> {
/** @suppress */
operator fun provideDelegate(receiver: Any?, prop: KProperty<Any?>): Lazy<V>
}
class KodeinProperty<out V>(internal val trigger: KodeinTrigger?, val originalContext: KodeinContext<*>, private val get: (KodeinContext<*>, String) -> V) : LazyDelegate<V> {
override fun provideDelegate(receiver: Any?, prop: KProperty<Any?>): Lazy<V> = lazy {
@Suppress("UNCHECKED_CAST")
val context = if (receiver != null && originalContext === AnyKodeinContext) KodeinContext(TTOf(receiver) as TypeToken<in Any>, receiver) else originalContext
get(context, prop.name) } .also { trigger?.properties?.add(it)
}
}
class KodeinPropertyMap<in I, out O>(private val base: KodeinProperty<I>, private val map: (I) -> O) : LazyDelegate<O> {
override fun provideDelegate(receiver: Any?, prop: KProperty<Any?>): Lazy<O> = lazy { map(base.provideDelegate(receiver, prop).value) }.also { base.trigger?.properties?.add(it) }
}
翻译一下:
假设一个var prop: Type by KodeinProperty()
=>
class C {
// calling "provideDelegate" to create the additional "delegate" property
private val prop$delegate = KodeinProperty().provideDelegate(this, this::prop)
val prop: Type
get() = prop$delegate.getValue(this, this::prop)
}
这里返回了lazy
,即当这个属性被用到时,会调用get
方法
那我们再来看看这段代码:
fun <A, T : Any> KodeinAware.Factory(argType: TypeToken<in A>, type: TypeToken<out T>, tag: Any? = null): KodeinProperty<(A) -> T> =
KodeinProperty(kodeinTrigger, kodeinContext) { ctx, _ -> kodein.container.factory(Kodein.Key(ctx.anyType, argType, type, tag), ctx.value) }
看源码可以看到Factory&Instance
的不同,前者lazy
返回一个N阶函数,后者lazy
直接返回一个实例。
所以很简单,就是通过kodein.container.factory
去获取。
KodeinContainerImpl
获取factory
,什么是工厂,就是别人传入一个A(arg)
返回自己需要的实例。
tree.find(key)
首先在树中根据键值寻找,kodein
在绑定关系的时候初始化了一个containerimpl
, 初始化了一颗树,
tree.find(key, 0).let {
if (it.size == 1) {
val (_, definition, translator) = it[0]
node?.check(key, 0)
val kContext = translator?.toKContext(context) ?: KodeinContext(key.contextType, context) as KodeinContext<Any>
key as Kodein.Key<Any, A, T>
val bindingKodein = bindingKodein(key, kContext, definition.tree, overrideLevel)
return definition.binding.getFactory(bindingKodein, key)
}
}
如果找到一个(有且一个),拿到definition
,即binding
的定义。检查是否有循环依赖
bindingKodein
val bindingKodein = bindingKodein(key, kContext, definition.tree, overrideLevel)
return definition.binding.getFactory(bindingKodein, key)
这里会创建一个bindingKodein
的东西,在bindings
去getFactory
,为什么要传入这么一个东西呢?
NoArgBindingKodeinWrap(BindingContextedKodein(kodein, kodein.context)).creator()
我们知道在实例化一个类时,这个类可能还会依赖其他类,绑定可能如下:
bind<AlbumDetailViewModel>() with scoped<Fragment>(AndroidLifecycleScope).singleton {
KotlinViewModelProvider.of(context) { AlbumDetailViewModel(instance(), instance()) }
}
在里面还需要instance()
实例化,那为什么不能直接用kodein
的环境呢,因为按官网说法,还可以进行override:
val testModule = Kodein.Module(name = "test") {
bind<Logger>(overrides = true) with singleton { FileLoggerWrapper("path/to/file", overriddenInstance()) }
}
所以其实bindingKodein
也是kodein
环境:
internal open class BindingKodeinImpl<out C, out A, out T: Any> internal constructor(
override val dkodein: DKodein,
private val _key: Kodein.Key<C, A, T>,
override val context: C,
private val _overrideLevel: Int
) : DKodein by dkodein, BindingKodein<C> {
override fun overriddenFactory(): (Any?) -> Any = container.factory(_key, context, _overrideLevel + 1) as (Any?) -> Any
override fun overriddenFactoryOrNull(): ((Any?) -> Any)? = container.factoryOrNull(_key, context, _overrideLevel + 1) as ((Any?) -> Any)?
}
它包括什么,它包括DKodien
, Dkodien
又是一个新的概念,
If you don’t want to use delegated properties, Kodein has you covered. Most of the features available to Kodein are available to DKodein (D is for Direct). DKodein allows you to directly get a new instance or dependency
它就比kodein
少了delegate
属性,因此也没有receiver & lazy
的概念。
override fun overriddenFactory(): (Any?) -> Any = container.factory(_key, context, _overrideLevel + 1) as (Any?) -> Any
正常绑定时使用的是container.factory(0)
,这里会使用+1
表明使用override
的
循环依赖 node.check
val kodein = Kodein {
bind<Die>() with singleton { Die(instance()) }
bind<Random>() with singleton { Random(instance) }
constant(tag "max") with 5
}
org.kodein.di.Kodein$DependencyLoopException: Dependency recursion:
bind<View>()
╔╩>bind<Presenter>()
║ ╚>bind<View>()
╚════╝
回顾一下,
,当我们调用by instance
时会发生什么,会返回一个函数,函数执行时会调用
kodein.container.provider(Kodein.Key(ctx.anyType, UnitToken, type, tag), ctx.value).invoke()
,即调用creator
,即Die(instance())
,这里调用instance()
时,背后调用DKodeinBaseImpl.container.provider.invoke()
,那这里的container是谁呢,
先看DKodeinBaseImpl
是谁,就是调用by instance
的container
,所以这里container
都是同一个,很正常能看出循环依赖。
我们看,在找factory时
,
private tailrec fun recursiveCheck(node: Node, searchedKey: Kodein.Key<*, *, *>, searchedOverrideLevel: Int): Boolean {
return if (node.key == searchedKey && node.overrideLevel == searchedOverrideLevel)
false
else if (node.parent == null)
true
else
recursiveCheck(node.parent, searchedKey, searchedOverrideLevel)
}
开始Node
是Die
, 然后Node
是Random
,然后 searchKey
是die
, 因此在递归上去时node -> parent
又是die
,导致循环依赖。
KodeinTreeImpl
一个缓存:
private val _cache: MutableMap<Kodein.Key<*, *, *>, Triple<Kodein.Key<*, *, *>, List<KodeinDefinition<*, *, *>>, ContextTranslator<*, *>?>>
private typealias BoundTypeTree = MutableMap<TypeChecker, ContextTypeTree>
private typealias ContextTypeTree = MutableMap<TypeChecker.Down, ArgumentTypeTree>
private typealias ArgumentTypeTree = MutableMap<TypeChecker.Down, TagTree>
private typealias TagTree = MutableMap<Any?, Kodein.Key<*, *, *>>
其中因为kodien
可以override
,所以会有definition lists
:
val kodein = Kodein {
bind<API>() with singleton { APIImpl() }
/* ... */
bind<API>(overrides = true) with singleton { OtherAPIImpl() }
}
寻找过程
-
_cache[key]
先从key
中寻找 -
_cache[anyContextKey]
寻找anyContextKey
当然translator.contextType = key.contextType
Inject or Retrieve
inject
class Controller(private val ds: DataSource) {
/*...*/
}
val controller by kodein.newInstance { Controller(instance()) }
这里会走到Controller(instance())
, 在instance
里会自己去取实例。
retrive
class Controller(override val kodein: Kodein): KodeinAware {
private val ds: DataSource by instance()
}
这两种方式,一种是自己就是一个kodein = KodeinAware
内部会去取实例,另一种是自己由外部注入。
SubTypes
val kodein = Kodein {
bind<Controller>().subtypes() with { type ->
when (type.jvmType) {
is MySpecialController::class.java -> singleton { MySpecialController() }
else -> provider { myControllerSystem.getController(type.jvmType) }
}
}
}
看到这里问题,我绑定的是T,这个T的子类也会找到:
data class Down(override val type: TypeToken<*>) : TypeChecker() {
val isAny = (type == AnyToken)
override fun check(other: TypeToken<*>) = isAny || type.isAssignableFrom(other)
}
Contexted & Scoped
在kodien
中,所有binder with binding
都会带一个scope&context
:对于默认的是AnyToken&NoScope
override val contextType = AnyToken
override val scope: Scope<Any?> get() = NoScope() // Recreating a new NoScope every-time *on purpose*!
那么,假设我们想要绑到一个具体的context&scope
时,可以按如下这么写:
val kodein = Kodein {
bind<Writer>() with contexted<Request>.provider { context.response.writer }
}
val kodein = Kodein {
bind<Session>() with scoped(requestScope).singleton { context.openSession() }
}
val session: Session by kodein.on(context = request).instance()
Scopes are derived from the context variable.
这里context<Request> & scoped(requestScope)
会返回一个新的builder
,绑定新的context&scope
, 当使用kodein.on
时会创建一个新的kodein
,kodeinContext
是传入的request
,我们再来重看一下getFactory
:
override fun getFactory(kodein: BindingKodein<C>, key: Kodein.Key<C, A, T>): (A) -> T {
val registry = scope.getRegistry(kodein.context)
return { arg ->
@Suppress("UNCHECKED_CAST")
registry.getOrCreate(ScopeKey(_scopeId, arg), sync) { _refMaker.make { BindingContextedKodein(kodein, kodein.context).creator(arg) } } as T
}
}
我们举个scope的例子:
open class AndroidLifecycleScope private constructor(private val newRegistry: () -> ScopeRegistry) : Scope<LifecycleOwner> {
companion object multiItem: AndroidLifecycleScope(::StandardScopeRegistry)
object singleItem: AndroidLifecycleScope(::SingleItemScopeRegistry)
private val map = HashMap<LifecycleOwner, ScopeRegistry>()
override fun getRegistry(context: LifecycleOwner): ScopeRegistry {
return synchronizedIfNull(
lock = map,
predicate = { map[context] },
ifNotNull = { it },
ifNull = {
val registry = newRegistry()
map[context] = registry
context.lifecycle.addObserver(object : LifecycleObserver {
@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
fun onDestroy() {
context.lifecycle.removeObserver(this)
registry.clear()
map.remove(context)
}
})
registry
}
)
}
}
TypedReference
- TypeVariable(类型变量):比如List<T>中的T等
- WildcardType( 泛型表达式类型):例如List< ? extends Number>这种
- ParameterizedType(参数化类型):就是我们平常所用到的泛型List、Map(注意和TypeVariable的区别)
- GenericArrayType(数组类型):并不是我们工作中所使用的数组String[] 、byte[](这种都属于Class),而是带有泛型的数组,即T[] 泛型数组
private fun Type._checkIsReified(disp: Any) {
when (val jvmType = javaType) {
is Class<*> -> {}
is ParameterizedType -> for (arg in jvmType.actualTypeArguments) arg._checkIsReified(disp)
is GenericArrayType -> jvmType.genericComponentType._checkIsReified(disp)
is WildcardType -> {
for (arg in jvmType.lowerBounds)
arg._checkIsReified(disp)
for (arg in jvmType.upperBounds)
arg._checkIsReified(disp)
}
is TypeVariable<*> -> throw IllegalArgumentException("$disp uses a type variable named ${jvmType.name}, therefore, the bound value can never be retrieved.")
else -> throw IllegalArgumentException("Unknown type ${jvmType.javaClass} $jvmType")
}
}
反正就是一定要具体化泛型,不要有<T>这种