You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
@@ -333,54 +333,6 @@ when you need to register routes depending on dynamic data (for example, from a
333
333
See https://github.com/mixitconf/mixit/[MiXiT project] for a concrete example.
334
334
335
335
336
-
337
-
=== Coroutines
338
-
339
-
As of Spring Framework 5.2, https://kotlinlang.org/docs/reference/coroutines-overview.html[Coroutines] support
340
-
is provided via:
341
-
342
-
* https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-deferred/index.html[Deferred] and https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/-flow/index.html[Flow] return value support in Spring WebFlux annotated `@Controller`
343
-
* Suspending function support in Spring WebFlux annotated `@Controller`
344
-
* Extensions for WebFlux {doc-root}/spring-framework/docs/{spring-version}/kdoc-api/spring-framework/org.springframework.web.reactive.function.client/index.html[client] and {doc-root}/spring-framework/docs/{spring-version}/kdoc-api/spring-framework/org.springframework.web.reactive.function.server/index.html[server] functional API.
and types like https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/-flow/index.html[`Flow`].
410
+
411
+
Spring Framework provides support for Coroutines on the following scope:
412
+
413
+
* https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-deferred/index.html[Deferred] and https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/-flow/index.html[Flow] return values support in Spring WebFlux annotated `@Controller`
414
+
* Suspending function support in Spring WebFlux annotated `@Controller`
415
+
* Extensions for WebFlux {doc-root}/spring-framework/docs/{spring-version}/kdoc-api/spring-framework/org.springframework.web.reactive.function.client/index.html[client] and {doc-root}/spring-framework/docs/{spring-version}/kdoc-api/spring-framework/org.springframework.web.reactive.function.server/index.html[server] functional API.
For return values, the translation from Reactive to Coroutines APIs is the following:
421
+
422
+
* `fun handler(): Mono<Void>` becomes `suspend fun handler()`
423
+
* `fun handler(): Mono<T>` becomes `suspend fun handler(): T` or `suspend fun handler(): T?` depending on if the `Mono` can be empty or not (with the advantage of beeing more statically typed)
* If laziness is not needed, `fun handler(mono: Mono<T>)` becomes `fun handler(value: T)` since a suspending functions can be invoked to get the value parameter.
429
+
* If laziness is needed, `fun handler(mono: Mono<T>)` becomes `fun handler(supplier: () -> T)` or `fun handler(supplier: () -> T?)`
430
+
431
+
https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/-flow/index.html[`Flow`] is `Flux` equivalent in Coroutines world, suitable for hot or cold stream, finite or infinite streams, with the following main differences:
432
+
433
+
* `Flow` is push-based while `Flux` is push-pull hybrid
434
+
* Backpressure is implemented via suspending functions
435
+
* `Flow` has only a https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/-flow/collect.html[single suspending `collect` method] and operators are implemented as https://kotlinlang.org/docs/reference/extensions.html[extensions]
436
+
* https://github.com/Kotlin/kotlinx.coroutines/tree/master/kotlinx-coroutines-core/common/src/flow/operators[Operators are easy to implement] thanks to Coroutines and extensions allow to add custom ones easily to `Flow`
437
+
* Collect operations are suspending functions
438
+
* `map` operator supports asynchronous operation (no need for `flatMap`) since it takes a suspending function parameter
439
+
440
+
Read this blog post about https://medium.com/@elizarov/structured-concurrency-722d765aa952[structured concurrency]
441
+
to understand how to run code concurrently with Coroutines and how are managed exceptions and cancellations.
442
+
443
+
=== Controllers
444
+
445
+
Here is an example of a Coroutines `@RestController`.
446
+
447
+
[source,kotlin,indent=0]
448
+
----
449
+
@RestController
450
+
class CoroutinesRestController(client: WebClient, banner: Banner) {
451
+
452
+
@GetMapping("/suspend")
453
+
suspend fun suspendingEndpoint(): Banner {
454
+
delay(10)
455
+
return banner
456
+
}
457
+
458
+
@GetMapping("/flow")
459
+
fun flowEndpoint() = flow {
460
+
delay(10)
461
+
emit(banner)
462
+
delay(10)
463
+
emit(banner)
464
+
}
465
+
466
+
@GetMapping("/deferred")
467
+
fun deferredEndpoint() = GlobalScope.async {
468
+
delay(10)
469
+
banner
470
+
}
471
+
472
+
@GetMapping("/sequential")
473
+
suspend fun sequential(): List<Banner> {
474
+
val banner1 = client
475
+
.get()
476
+
.uri("/suspend")
477
+
.accept(MediaType.APPLICATION_JSON)
478
+
.awaitExchange()
479
+
.awaitBody<Banner>()
480
+
val banner2 = client
481
+
.get()
482
+
.uri("/suspend")
483
+
.accept(MediaType.APPLICATION_JSON)
484
+
.awaitExchange()
485
+
.awaitBody<Banner>()
486
+
return listOf(banner1, banner2)
487
+
}
488
+
489
+
@GetMapping("/parallel")
490
+
suspend fun parallel(): List<Banner> = coroutineScope {
View rendering with a `@Controller` is also supported.
524
+
525
+
[source,kotlin,indent=0]
526
+
----
527
+
@Controller
528
+
class CoroutinesViewController(banner: Banner) {
529
+
530
+
@GetMapping("/")
531
+
suspend fun render(model: Model): String {
532
+
delay(10)
533
+
model["banner"] = banner
534
+
return "index"
535
+
}
536
+
}
537
+
----
538
+
539
+
=== WebFlux.fn
540
+
541
+
Here is an example of Coroutines router definined via the {doc-root}/spring-framework/docs/{spring-version}/kdoc-api/spring-framework/org.springframework.web.reactive.function.server/co-router.html[coRouter { }] DSL and related handlers.
542
+
543
+
[source,kotlin,indent=0]
544
+
----
545
+
@Configuration
546
+
class RouterConfiguration {
547
+
548
+
@Bean
549
+
fun mainRouter(userHandler: UserHandler) = coRouter {
550
+
GET("/", userHandler::listView)
551
+
GET("/api/user", userHandler::listApi)
552
+
}
553
+
}
554
+
----
555
+
556
+
[source,kotlin,indent=0]
557
+
----
558
+
class UserHandler(builder: WebClient.Builder) {
559
+
560
+
private val client = builder.baseUrl("...").build()
561
+
562
+
suspend fun listView(request: ServerRequest): ServerResponse =
563
+
ServerResponse.ok().renderAndAwait("users", mapOf("users" to
0 commit comments