Defining Services
Kontainer supports three service lifecycles — Singleton, Dynamic, and Prototype — plus existing instances and interface-based registration.
Singleton
A singleton is created once and shared across all container instances created from the same blueprint.
class Counter {
private var count = 0
fun next() = ++count
}
val blueprint = kontainer {
singleton(Counter::class)
}
// Same instance across all containers from this blueprint
val k1 = blueprint.create()
val k2 = blueprint.create()
println(k1.get(Counter::class).next()) // 1
println(k2.get(Counter::class).next()) // 2 (same instance!) Dynamic
A dynamic service is a singleton within a single container instance. Each new container gets its own fresh instance.
val blueprint = kontainer {
dynamic(Counter::class)
}
val k1 = blueprint.create()
val k2 = blueprint.create()
println(k1.get(Counter::class).next()) // 1
println(k1.get(Counter::class).next()) // 2 (same instance within k1)
println(k2.get(Counter::class).next()) // 1 (fresh instance in k2) Dynamic services are the key to per-request scoping.
Prototype
A prototype creates a new instance every time it is requested — whether retrieved directly or injected.
val blueprint = kontainer {
prototype(Counter::class)
}
val kontainer = blueprint.create()
println(kontainer.get(Counter::class).next()) // 1
println(kontainer.get(Counter::class).next()) // 1 (new instance each time!) Existing instances
Register an already-created object as a singleton:
object AppConfig {
val dbUrl = "jdbc:postgresql://localhost/mydb"
}
val blueprint = kontainer {
instance(AppConfig)
} Hiding implementations behind interfaces
Register a service under its interface so consumers never see the concrete class:
interface GreeterInterface {
fun sayHello(): String
}
class Greeter : GreeterInterface {
override fun sayHello() = "Hello!"
}
val blueprint = kontainer {
// Registered as GreeterInterface — Greeter is hidden
singleton(GreeterInterface::class, Greeter::class)
}
val kontainer = blueprint.create()
kontainer.get(GreeterInterface::class) // works
kontainer.get(Greeter::class) // throws ServiceNotFound This pattern works with all lifecycle types: singleton, dynamic, prototype, instance, and factory methods.