CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-io-insert-koin--koin-core

Koin is a pragmatic lightweight dependency injection framework for Kotlin developers, providing core dependency injection functionality for Kotlin Multiplatform projects.

Pending
Overview
Eval results
Files

module-dsl.mddocs/

Module DSL and Definition

The Koin DSL provides a declarative way to define dependency injection modules using Kotlin's DSL capabilities. Modules contain dependency definitions that specify how objects are created and managed.

Core Module Creation

fun module(createdAtStart: Boolean = false, moduleDeclaration: ModuleDeclaration): Module

typealias ModuleDeclaration = Module.() -> Unit

The module function creates a new Koin module. The createdAtStart parameter determines if all singleton instances in this module should be created eagerly when the module is loaded.

Usage Example

val myModule = module {
    single<DatabaseService> { DatabaseServiceImpl() }
    factory<UserRepository> { UserRepositoryImpl(get()) }
}

// Module with eager initialization
val eagerModule = module(createdAtStart = true) {
    single<AppConfig> { AppConfigImpl() }
}

Dependency Definition Types

Single (Singleton)

Creates a single instance that is shared across the entire application lifecycle.

inline fun <reified T> Module.single(
    qualifier: Qualifier? = null,
    createdAtStart: Boolean = false,
    noinline definition: Definition<T>
): KoinDefinition<T>

Parameters:

  • qualifier: Optional qualifier to distinguish between multiple implementations
  • createdAtStart: If true, creates the instance immediately when the module loads
  • definition: Factory function that creates the instance

Factory

Creates a new instance each time it's requested.

inline fun <reified T> Module.factory(
    qualifier: Qualifier? = null,
    noinline definition: Definition<T>
): KoinDefinition<T>

Parameters:

  • qualifier: Optional qualifier to distinguish between multiple implementations
  • definition: Factory function that creates the instance

Scoped

Creates instances that are tied to a specific scope lifecycle.

inline fun <reified T> ScopeDSL.scoped(
    qualifier: Qualifier? = null,
    noinline definition: Definition<T>
): KoinDefinition<T>

Constructor-Based DSL Functions

Koin provides constructor-based DSL functions that offer a more direct way to declare dependencies using constructor references.

SingleOf

Creates a singleton instance using a constructor reference.

inline fun <reified R> Module.singleOf(
    crossinline constructor: () -> R,
    noinline options: DefinitionOptions<R>? = null
): KoinDefinition<R>

inline fun <reified R, reified T1> Module.singleOf(
    crossinline constructor: (T1) -> R,
    noinline options: DefinitionOptions<R>? = null
): KoinDefinition<R>

inline fun <reified R, reified T1, reified T2> Module.singleOf(
    crossinline constructor: (T1, T2) -> R,
    noinline options: DefinitionOptions<R>? = null
): KoinDefinition<R>

// Additional overloads for more parameters...

FactoryOf

Creates a factory instance using a constructor reference.

inline fun <reified R> Module.factoryOf(
    crossinline constructor: () -> R,
    noinline options: DefinitionOptions<R>? = null
): KoinDefinition<R>

inline fun <reified R, reified T1> Module.factoryOf(
    crossinline constructor: (T1) -> R,
    noinline options: DefinitionOptions<R>? = null
): KoinDefinition<R>

inline fun <reified R, reified T1, reified T2> Module.factoryOf(
    crossinline constructor: (T1, T2) -> R,
    noinline options: DefinitionOptions<R>? = null
): KoinDefinition<R>

// Additional overloads for more parameters...

ScopedOf

Creates a scoped instance using a constructor reference.

inline fun <reified R> ScopeDSL.scopedOf(
    crossinline constructor: () -> R,
    noinline options: DefinitionOptions<R>? = null
): KoinDefinition<R>

inline fun <reified R, reified T1> ScopeDSL.scopedOf(
    crossinline constructor: (T1) -> R,
    noinline options: DefinitionOptions<R>? = null
): KoinDefinition<R>

inline fun <reified R, reified T1, reified T2> ScopeDSL.scopedOf(
    crossinline constructor: (T1, T2) -> R,
    noinline options: DefinitionOptions<R>? = null
): KoinDefinition<R>

// Additional overloads for more parameters...

Constructor-Based Usage Examples

val myModule = module {
    // Using constructor references instead of lambdas
    singleOf(::DatabaseServiceImpl)
    factoryOf(::UserRepositoryImpl)
    
    // With multiple dependencies
    singleOf(::UserServiceImpl) // constructor takes DatabaseService, UserRepository
    
    scope<UserSession> {
        scopedOf(::SessionDataImpl)
        scopedOf(::UserPreferencesImpl)
    }
}

// Equivalent to:
val traditionalModule = module {
    single<DatabaseServiceImpl> { DatabaseServiceImpl() }
    factory<UserRepositoryImpl> { UserRepositoryImpl() }
    single<UserServiceImpl> { UserServiceImpl(get(), get()) }
    
    scope<UserSession> {
        scoped<SessionDataImpl> { SessionDataImpl() }
        scoped<UserPreferencesImpl> { UserPreferencesImpl() }
    }
}

Definition Function

typealias Definition<T> = Scope.(ParametersDefinition?) -> T

The definition function is a lambda that creates instances. It receives:

  • Scope: The current scope for resolving dependencies
  • ParametersDefinition?: Optional parameters passed during injection

Dependency Resolution

Within definition functions, use get() to resolve dependencies:

val myModule = module {
    single<Database> { DatabaseImpl() }
    single<UserService> { UserServiceImpl(get<Database>()) }
    
    // With qualifier
    single<Cache>(named("user-cache")) { UserCacheImpl() }
    single<UserRepository> { 
        UserRepositoryImpl(get<Database>(), get<Cache>(named("user-cache"))) 
    }
}

Scope Definition

fun Module.scope(qualifier: Qualifier, scopeSet: ScopeDSL.() -> Unit)

inline fun <reified T> Module.scope(scopeSet: ScopeDSL.() -> Unit)

Scopes group dependencies with a shared lifecycle:

val myModule = module {
    scope<UserSession> {
        scoped<SessionData> { SessionDataImpl() }
        scoped<UserPreferences> { UserPreferencesImpl(get()) }
    }
    
    // Named scope
    scope(named("http-client")) {
        scoped<HttpClient> { HttpClientImpl() }
        scoped<ApiService> { ApiServiceImpl(get()) }
    }
}

Qualifiers

Qualifiers distinguish between multiple implementations of the same type.

interface Qualifier {
    val value: String
}

class StringQualifier(override val value: String) : Qualifier
class TypeQualifier(val kclass: KClass<*>) : Qualifier

fun named(name: String): StringQualifier

Usage Examples

val myModule = module {
    // Multiple implementations with qualifiers
    single<Database>(named("primary")) { PrimaryDatabaseImpl() }
    single<Database>(named("cache")) { CacheDatabaseImpl() }
    
    // Type-based qualifier
    single<Logger>(qualifier<ConsoleLogger>()) { ConsoleLoggerImpl() }
    single<Logger>(qualifier<FileLogger>()) { FileLoggerImpl() }
}

KoinDefinition Extensions

class KoinDefinition<T>(val module: Module, val beanDefinition: BeanDefinition<T>) {
    inline fun <reified Type> bind(): KoinDefinition<T>
    fun createdAtStart(): BeanDefinition<T>
}

The KoinDefinition class allows chaining additional configuration:

val myModule = module {
    single<UserServiceImpl> { UserServiceImpl(get()) }
        .bind<UserService>()  // Bind to interface
        .bind<Auditable>()    // Bind to additional interface
        
    single<DatabaseService> { DatabaseServiceImpl() }
        .createdAtStart()     // Create eagerly
}

Module Composition

fun Module.includes(vararg module: Module)
fun Module.includes(module: Collection<Module>)

operator fun Module.plus(module: Module): List<Module>
operator fun Module.plus(modules: List<Module>): List<Module>

Combine modules for better organization:

val databaseModule = module {
    single<Database> { DatabaseImpl() }
}

val serviceModule = module {
    includes(databaseModule)
    single<UserService> { UserServiceImpl(get()) }
}

// Using operators
val allModules = databaseModule + serviceModule

Advanced Features

Parameters

Pass parameters during injection:

val myModule = module {
    factory<UserService> { params ->
        val userId = params.get<String>()
        UserServiceImpl(userId, get())
    }
}

// Usage
val userService = get<UserService> { parametersOf("user123") }

Conditional Definition

val myModule = module {
    single<Logger> {
        if (BuildConfig.DEBUG) {
            ConsoleLogger()
        } else {
            FileLogger()
        }
    }
}

Install with Tessl CLI

npx tessl i tessl/maven-io-insert-koin--koin-core

docs

application.md

components.md

index.md

module-dsl.md

scopes.md

tile.json