Global & Configurable Kodein DI
Introduction
The Configurable DI Plugin gives you :
-
A
ConfigurableDI
class that you can pass around and have different sections of your code configure its bindings. -
A
DI.global
instance that allows to have "one true" source.
The Configurable DI Plugin is an extension that is not proposed by default, this paradigm is in a separate module.
Using or not using this is a matter of taste and is neither recommended nor discouraged. |
Install
JVM
With Gradle
If you are NOT using Gradle 6+, you should declare the use of the Gradle Metadata experimental feature settings.gradle.kts
enableFeaturePreview("GRADLE_METADATA") |
Add the MavenCentral repository:
buildscript {
repositories {
mavenCentral()
}
}
Then add the dependency:
dependencies {
implementation 'org.kodein.di:kodein-conf-di:7.8.0'
}
Add the dependency:
<dependencies>
<dependency>
<groupId>org.kodein.di</groupId>
<artifactId>kodein-di-jvm</artifactId>
<version>7.8.0</version>
</dependency>
</dependencies>
Use kodein-di-conf-jvm , as Kotlin/Multiplatform projects does not work with Maven
|
JavaScript (Gradle)
Because Kodein-DI for JavaScript is compiled as a UMD module, it can be imported:
-
In a browser:
-
as an AMD module (for example with RequireJS) (See index.html in the demo project).
-
Directly in an HTML page with a
<script>
tag (See index2.html in the demo project).
-
-
In NodeJS, as a regular CJS module.
Add the MavenCentral repository:
buildscript {
repositories {
mavenCentral()
}
}
Then add the dependency:
dependencies {
compile 'org.kodein.di:kodein-di-conf-js:7.8.0'
}
Kotlin/Multiplatform (Gradle)
Kodein-DI supports the following targets: androidArm32, androidArm64, iosArm32, iosArm64, iosX64, linuxArm32Hfp, linuxMips32, linuxMipsel32, linuxX64, macosX64, mingwX64 |
Kodein-DI uses the new gradle native dependency model.
Add the MavenCentral repository:
buildscript {
repositories {
mavenCentral()
}
}
Then add the dependency:
kotlin {
sourceSets {
commonMain {
dependencies {
implementation "org.kodein.di:kodein-di-conf:7.8.0"
}
}
}
}
ConfigurableDI
Configuring
You can import modules, extend DI objects, or add bindings inside this ConfigurableDI
using addImport
, addExtend
and addConfig
.
fun test() {
val di = ConfigurableDI()
di.addModule(aModule)
di.addExtend(otherDI)
di.addConfig {
bind<Dice> { provider { RandomDice(0, 5) } }
bind<DataSource> { singleton { SqliteDS.open("path/to/file") } }
}
}
The DI underlying instance will effectively be constructed on first retrieval.
Once it is constructed, trying to configure it will throw an IllegalStateException .
|
Retrieving
You can use a ConfigurableDI
object like any DI
object.
Once you have retrieved the first value with a ConfigurableDI , trying to configure it will throw an IllegalStateException .
|
Mutating
A ConfigurableDI
can be mutable.
val di = ConfigurableDI(mutable = true)
Using a mutable |
A mutable ConfigurableDI
can be configured even after first retrieval.
fun test() {
val di = ConfigurableDI(mutable = true)
di.addModule(aModule)
val ds: DataSource by di.instance()
di.addModule(anotherModule) (1)
}
1 | This would have failed if the ConfigurableDI was not mutable. |
You can also use the clear
method to remove all bindings.
The god complex: One True DI
Sometimes, you want one static DI for your entire application. E.g. you don’t want to have to hold & pass a DI instance throughout your application.
For these cases, the di-conf
module proposes a static DI.global
instance.
fun test() {
DI.global.addModule(apiModule)
DI.global.addModule(dbModule)
val ds: DataSource by DI.global.instance()
}
Just like any |