diff --git a/docs/reference/koin-ktor/ktor-isolated.md b/docs/reference/koin-ktor/ktor-isolated.md new file mode 100644 index 000000000..8312ba673 --- /dev/null +++ b/docs/reference/koin-ktor/ktor-isolated.md @@ -0,0 +1,27 @@ +--- +title: Ktor & Koin Isolated Context +--- + +The `koin-ktor` module is dedicated to bring dependency injection for Ktor. + + +## Isolated Koin Context Plugin + +To start an Isolated Koin container in Ktor, just install the `KoinIsolated` plugin like follow: + +```kotlin +fun Application.main() { + // Install Koin plugin + install(KoinIsolated) { + slf4jLogger() + modules(helloAppModule) + } +} +``` + +:::warning + By using an isolated Koin context you won't be able to use Koin outside of Ktor server instance (i.e: by using `GlobalContext` for example) +::: + + + diff --git a/docs/reference/koin-ktor/ktor.md b/docs/reference/koin-ktor/ktor.md index b3b09038d..5b8995728 100644 --- a/docs/reference/koin-ktor/ktor.md +++ b/docs/reference/koin-ktor/ktor.md @@ -1,5 +1,5 @@ --- -title: Ktor dependency injection with Koin +title: Dependency Injection in Ktor --- The `koin-ktor` module is dedicated to bring dependency injection for Ktor. @@ -10,7 +10,7 @@ To start a Koin container in Ktor, just install the `Koin` plugin like follow: ```kotlin fun Application.main() { - // Install Ktor features + // Install Koin install(Koin) { slf4jLogger() modules(helloAppModule) @@ -19,11 +19,6 @@ fun Application.main() { } ``` -:::note - Koin Ktor plugin uses isolated Koin context. You won't be able to start Koin outside of Ktor -::: - - ## Inject in Ktor Koin `inject()` and `get()` functions are available from `Application`,`Route`,`Routing` classes: diff --git a/ktor/gradle/versions.gradle b/ktor/gradle/versions.gradle index 917bf1beb..de2851af5 100644 --- a/ktor/gradle/versions.gradle +++ b/ktor/gradle/versions.gradle @@ -1,6 +1,6 @@ ext { // Koin - koin_ktor_version = '3.5.1' + koin_ktor_version = '3.5.2' // Ktor - ktor_version = '2.3.3' + ktor_version = '2.3.6' } \ No newline at end of file diff --git a/ktor/koin-ktor/src/main/kotlin/org/koin/ktor/ext/ApplicationCallExt.kt b/ktor/koin-ktor/src/main/kotlin/org/koin/ktor/ext/ApplicationCallExt.kt index 75c54b80d..e429c5efe 100644 --- a/ktor/koin-ktor/src/main/kotlin/org/koin/ktor/ext/ApplicationCallExt.kt +++ b/ktor/koin-ktor/src/main/kotlin/org/koin/ktor/ext/ApplicationCallExt.kt @@ -19,10 +19,6 @@ import io.ktor.server.application.* import org.koin.core.Koin import org.koin.core.parameter.ParametersDefinition import org.koin.core.qualifier.Qualifier -import org.koin.core.scope.Scope -import org.koin.ktor.plugin.KOIN_ATTRIBUTE_KEY -import org.koin.ktor.plugin.KOIN_KEY -import org.koin.ktor.plugin.KOIN_SCOPE_ATTRIBUTE_KEY /** * Ktor Koin extensions for ApplicationCall class diff --git a/ktor/koin-ktor/src/main/kotlin/org/koin/ktor/plugin/KoinIsolatedContextPlugin.kt b/ktor/koin-ktor/src/main/kotlin/org/koin/ktor/plugin/KoinIsolatedContextPlugin.kt new file mode 100644 index 000000000..b0525fe7e --- /dev/null +++ b/ktor/koin-ktor/src/main/kotlin/org/koin/ktor/plugin/KoinIsolatedContextPlugin.kt @@ -0,0 +1,34 @@ +/* + * Copyright 2017-2023 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.koin.ktor.plugin + +import io.ktor.server.application.* +import org.koin.core.KoinApplication +import org.koin.core.annotation.KoinInternalApi + +/** + * @author Arnaud Giuliani + * + * Ktor Feature class. Allows Koin Isolatd Context to start using Ktor default install() method. + * + */ +@OptIn(KoinInternalApi::class) +val KoinIsolated = createApplicationPlugin(name = "Koin", createConfiguration = { KoinApplication.init() }) { + val koinApplication = setupKoinApplication() + setupMonitoring(koinApplication) + setupKoinScope(koinApplication) + koinApplication.koin.logger.info("Koin is using Ktor isolated context") +} diff --git a/ktor/koin-ktor/src/main/kotlin/org/koin/ktor/plugin/KoinPlugin.kt b/ktor/koin-ktor/src/main/kotlin/org/koin/ktor/plugin/KoinPlugin.kt index 3b5863b57..e8606957c 100644 --- a/ktor/koin-ktor/src/main/kotlin/org/koin/ktor/plugin/KoinPlugin.kt +++ b/ktor/koin-ktor/src/main/kotlin/org/koin/ktor/plugin/KoinPlugin.kt @@ -19,6 +19,7 @@ import io.ktor.server.application.* import io.ktor.server.application.hooks.* import io.ktor.util.* import org.koin.core.KoinApplication +import org.koin.core.context.startKoin import org.koin.core.scope.Scope import org.koin.dsl.KoinAppDeclaration @@ -28,16 +29,17 @@ import org.koin.dsl.KoinAppDeclaration * @author Victor Alenkov * @author Zak Henry * - * Ktor Feature class. Allows Koin Context to start using Ktor default install() method. + * Ktor Feature class. Allows Koin Standard Context to start using Ktor default install() method. * */ val Koin = createApplicationPlugin(name = "Koin", createConfiguration = { KoinApplication.init() }) { val koinApplication = setupKoinApplication() + startKoin(koinApplication) setupMonitoring(koinApplication) setupKoinScope(koinApplication) } -private fun PluginBuilder.setupKoinApplication(): KoinApplication { +internal fun PluginBuilder.setupKoinApplication(): KoinApplication { val koinApplication = pluginConfig koinApplication.createEagerInstances() application.setKoinApplication(koinApplication) @@ -48,7 +50,7 @@ fun Application.setKoinApplication(koinApplication: KoinApplication){ attributes.put(KOIN_ATTRIBUTE_KEY, koinApplication) } -private fun PluginBuilder.setupMonitoring(koinApplication: KoinApplication) { +internal fun PluginBuilder.setupMonitoring(koinApplication: KoinApplication) { val monitor = environment?.monitor monitor?.raise(KoinApplicationStarted, koinApplication) monitor?.subscribe(ApplicationStopping) { @@ -58,7 +60,7 @@ private fun PluginBuilder.setupMonitoring(koinApplication: Koin } } -private fun PluginBuilder.setupKoinScope(koinApplication: KoinApplication) { +internal fun PluginBuilder.setupKoinScope(koinApplication: KoinApplication) { // Scope Handling on(CallSetup) { call -> val scopeComponent = RequestScope(koinApplication.koin) diff --git a/ktor/koin-ktor/src/test/kotlin/org/koin/ktor/ext/KoinFeatureTest.kt b/ktor/koin-ktor/src/test/kotlin/org/koin/ktor/ext/KoinFeatureTest.kt index 9af916a60..9dceabffb 100644 --- a/ktor/koin-ktor/src/test/kotlin/org/koin/ktor/ext/KoinFeatureTest.kt +++ b/ktor/koin-ktor/src/test/kotlin/org/koin/ktor/ext/KoinFeatureTest.kt @@ -1,92 +1,57 @@ -//package org.koin.ktor.ext -// -//import io.ktor.application.* -//import io.ktor.server.testing.* -//import org.junit.Assert.* -//import org.junit.Ignore -//import org.junit.Test -//import org.koin.core.annotation.KoinReflectAPI -//import org.koin.core.context.GlobalContext -//import org.koin.core.context.loadKoinModules -//import org.koin.core.instance.newInstance -//import org.koin.core.parameter.emptyParametersHolder -//import org.koin.dsl.module -//import org.koin.dsl.single -// -///** -// * @author vinicius -// * @author Victor Alenkov -// * -// */ -//class Foo(val name: String = "") -//class Bar(val name: String = "") -//class Bar2(val name: String = "") -// -//@OptIn(KoinReflectAPI::class) -//class KoinFeatureTest { -// -// @Test -// fun `can install feature`() { -// val module = module { -// single { Foo("bar") } -// } -// withApplication { -// application.install(Koin) { -// modules(module) -// } -// val bean = GlobalContext.get().get() -// assertNotNull(bean) -// } -// } -// -// @Test -// fun `Koin does not contain modules`() { -// withApplication { -// assertNull(GlobalContext.getOrNull()) -// assertNull(application.featureOrNull(Koin)) -// -// application.install(Koin) -// assertNotNull(application.featureOrNull(Koin)) -// val koin = GlobalContext.getOrNull() -// assertNotNull(koin) -// requireNotNull(koin) -// -// assertNull(koin.getOrNull()) -// } -// } -// -// @Test -// fun `add a Koin module to an already running application`() { -// withApplication { -// application.install(Koin) -// val koin = application.getKoin() -// -// assertNull(koin.getOrNull()) -// -// application.featureOrNull(Koin)?.let { -// loadKoinModules(module { -// single() -// }) -// } -// assertNotNull(koin.getOrNull()) -// } -// } -// -// @Test -// fun `Using the koin extension`() { -// withApplication { -// assertNull(GlobalContext.getOrNull()) -// assertNull(application.featureOrNull(Koin)) -// -// application.koin { -// modules(module { -// single() -// }) -// } -// assertNotNull(application.getKoin().getOrNull()) -// } -// } -// +package org.koin.ktor.ext + +import io.ktor.server.application.* +import io.ktor.server.testing.* +import org.junit.Assert.* +import org.junit.Test +import org.koin.core.annotation.KoinReflectAPI +import org.koin.dsl.module +import org.koin.ktor.plugin.Koin +import org.koin.ktor.plugin.KoinIsolated +import org.koin.mp.KoinPlatform + +/** + * @author vinicius + * @author Victor Alenkov + * + */ +class Foo(val name: String = "") +class Bar(val name: String = "") +class Bar2(val name: String = "") + +@OptIn(KoinReflectAPI::class) +class KoinFeatureTest { + + @Test + fun `can install feature`() { + val module = module { + single { Foo("bar") } + } + withApplication { + application.install(Koin) { + modules(module) + } + val bean = KoinPlatform.getKoin().getOrNull() + assertNotNull(bean) + } + } + + @Test + fun `can install feature - isolated context`() { + val module = module { + single { Foo("bar") } + } + withApplication { + application.install(KoinIsolated) { + modules(module) + } + val bean1 = application.get() + assertNotNull(bean1) + val bean2 = runCatching { KoinPlatform.getKoin().getOrNull() }.getOrNull() + assertNull(bean2) + } + } + // @Test // fun `Using the koinModules extension`() { // withApplication { @@ -213,4 +178,4 @@ // } // assertEquals(4, c) // } -//} +}