Add Coroutines support for WebClient and WebFlux.fn
This commit is the first part of a more complete Coroutines
support coming in Spring Framework 5.2. It introduces suspendable
Kotlin extensions for Mono based methods in WebFlux classes like
WebClient, ServerRequest, ServerResponse as well as a Coroutines
router usable via `coRouter { }`.
Coroutines extensions use `await` prefix or `AndAwait` suffix,
and most are using names close to their Reactive counterparts,
except `exchange` in `WebClient.RequestHeadersSpec`
which translates to `awaitResponse`.
Upcoming expected changes are:
- Leverage `Dispatchers.Unconfined` (Kotlin/kotlinx.coroutines#972)
- Expose extensions for `Flux` based API (Kotlin/kotlinx.coroutines#254)
- Introduce interop with `CoroutineContext` (Kotlin/kotlinx.coroutines#284)
- Support Coroutines in `ReactiveAdapterRegistry`
- Support Coroutines for WebFlux annotated controllers
- Fix return type of Kotlin suspending functions (gh-21058)
See gh-19975
This commit is contained in:
@@ -20,10 +20,10 @@ https://stackoverflow.com/questions/tagged/spring+kotlin[Stackoverflow] if you n
|
||||
[[kotlin-requirements]]
|
||||
== Requirements
|
||||
|
||||
The Spring Framework supports Kotlin 1.1+ and requires
|
||||
The Spring Framework supports Kotlin 1.3+ and requires
|
||||
https://bintray.com/bintray/jcenter/org.jetbrains.kotlin%3Akotlin-stdlib[`kotlin-stdlib`]
|
||||
(or one of its variants, such as https://bintray.com/bintray/jcenter/org.jetbrains.kotlin%3Akotlin-stdlib-jre8[`kotlin-stdlib-jre8`]
|
||||
for Kotlin 1.1 or https://bintray.com/bintray/jcenter/org.jetbrains.kotlin%3Akotlin-stdlib-jdk8[`kotlin-stdlib-jdk8`] for Kotlin 1.2+)
|
||||
(or one of its variants, such as
|
||||
https://bintray.com/bintray/jcenter/org.jetbrains.kotlin%3Akotlin-stdlib-jdk8[`kotlin-stdlib-jdk8`])
|
||||
and https://bintray.com/bintray/jcenter/org.jetbrains.kotlin%3Akotlin-reflect[`kotlin-reflect`]
|
||||
to be present on the classpath. They are provided by default if you bootstrap a Kotlin project on
|
||||
https://start.spring.io/#!language=kotlin[start.spring.io].
|
||||
@@ -255,17 +255,19 @@ for more details and up-to-date information.
|
||||
== Web
|
||||
|
||||
|
||||
=== WebFlux router DSL
|
||||
|
||||
=== WebFlux Functional DSL
|
||||
Spring Framework comes with a Kotlin router DSL available in 2 flavors:
|
||||
|
||||
Spring Framework now comes with a
|
||||
{doc-root}/spring-framework/docs/{spring-version}/kdoc-api/spring-framework/org.springframework.web.reactive.function.server/-router-function-dsl/[Kotlin routing DSL]
|
||||
that lets you use the <<web-reactive#webflux-fn,WebFlux functional API>> to write clean and idiomatic Kotlin code,
|
||||
as the following example shows:
|
||||
- Reactive with {doc-root}/spring-framework/docs/{spring-version}/kdoc-api/spring-framework/org.springframework.web.reactive.function.server/-router-function-dsl/[router { }]
|
||||
- <<Coroutines>>
|
||||
|
||||
These DSL let you use the <<web-reactive#webflux-fn,WebFlux functional API>> to write clean and idiomatic Kotlin code
|
||||
to build a `RouterFunction` instance as the following example shows:
|
||||
|
||||
[source,kotlin,indent=0]
|
||||
----
|
||||
router {
|
||||
val routes: RouterFunction<ServerResponse> = router {
|
||||
accept(TEXT_HTML).nest {
|
||||
GET("/") { ok().render("index") }
|
||||
GET("/sse") { ok().render("sse") }
|
||||
@@ -290,7 +292,38 @@ depending on dynamic data (for example, from a database).
|
||||
See https://github.com/mixitconf/mixit/tree/dafd5ccc92dfab6d9c306fcb60b28921a1ccbf79/src/main/kotlin/mixit/web/routes[MiXiT project routes]
|
||||
for a concrete example.
|
||||
|
||||
=== Coroutines
|
||||
|
||||
As of Spring Framework 5.2, https://kotlinlang.org/docs/reference/coroutines-overview.html[Coroutines support]
|
||||
is provided via extensions for WebFlux client and server functional API. A dedicated
|
||||
{doc-root}/spring-framework/docs/{spring-version}/kdoc-api/spring-framework/org.springframework.web.reactive.function.server/-co-router-function-dsl/[`coRouter { }`]
|
||||
router DSL is also available.
|
||||
|
||||
Coroutines extensions use `await` prefix or `AndAwait` suffix, and most are using similar name than their Reactive
|
||||
counterparts except `exchange` in `WebClient.RequestHeadersSpec` which translates to `awaitResponse`.
|
||||
|
||||
[source,kotlin,indent=0]
|
||||
----
|
||||
fun routes(userHandler: UserHandler): RouterFunction<ServerResponse> = coRouter {
|
||||
GET("/", userHandler::listView)
|
||||
GET("/api/user", userHandler::listApi)
|
||||
}
|
||||
|
||||
class UserHandler(private val client: WebClient) {
|
||||
|
||||
suspend fun listApi(request: ServerRequest): ServerResponse =
|
||||
ServerResponse.ok().contentType(MediaType.APPLICATION_JSON_UTF8).bodyAndAwait(
|
||||
client.get().uri("...").awaitResponse().awaitBody<User>())
|
||||
|
||||
suspend fun listView(request: ServerRequest): ServerResponse =
|
||||
ServerResponse.ok().renderAndAwait("users", mapOf("users" to
|
||||
client.get().uri("...").awaitResponse().awaitBody<User>()))
|
||||
|
||||
}
|
||||
----
|
||||
|
||||
Read this https://medium.com/@elizarov/structured-concurrency-722d765aa952[structured concurrency blog post]
|
||||
to understand how to run code concurrently with Coroutines.
|
||||
|
||||
=== Kotlin Script Templates
|
||||
|
||||
|
||||
Reference in New Issue
Block a user