Coroutines

Kotlin Coroutines 是轻量级线程,允许强制性地编写非阻塞代码。在语言方面,suspend 函数为异步操作提供了一个抽象,而 kotlinx.coroutines 在库方面提供了 async { } 等函数和 Flow 等类型。

Kotlin Coroutines are lightweight threads allowing to write non-blocking code imperatively. On language side, suspend functions provides an abstraction for asynchronous operations while on library side kotlinx.coroutines provides functions like async { } and types like Flow.

Spring Data 模块为以下范围内的协程提供支持:

Spring Data modules provide support for Coroutines on the following scope:

  • Deferred and Flow return values support in Kotlin extensions

Dependencies

kotlinx-coroutines-corekotlinx-coroutines-reactivekotlinx-coroutines-reactor 依赖项在 classpath 中时,协程支持处于启用状态:

Coroutines support is enabled when kotlinx-coroutines-core, kotlinx-coroutines-reactive and kotlinx-coroutines-reactor dependencies are in the classpath:

Dependencies to add in Maven pom.xml
<dependency>
	<groupId>org.jetbrains.kotlinx</groupId>
	<artifactId>kotlinx-coroutines-core</artifactId>
</dependency>

<dependency>
	<groupId>org.jetbrains.kotlinx</groupId>
	<artifactId>kotlinx-coroutines-reactive</artifactId>
</dependency>

<dependency>
	<groupId>org.jetbrains.kotlinx</groupId>
	<artifactId>kotlinx-coroutines-reactor</artifactId>
</dependency>

支持版本 1.3.0 及更高版本。

Supported versions 1.3.0 and above.

How Reactive translates to Coroutines?

对于返回值,从 Reactive 到协程 API 的转换如下所示:

For return values, the translation from Reactive to Coroutines APIs is the following:

  • fun handler(): Mono<Void> becomes suspend fun handler()

  • 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 being more statically typed)

  • fun handler(): Flux<T> becomes fun handler(): Flow<T>

Flow 是 Coroutines 世界中 Flux 的等价物,适用于热流或冷流、有限流或无限流,具有以下主要区别:

Flow is Flux equivalent in Coroutines world, suitable for hot or cold stream, finite or infinite streams, with the following main differences:

  • Flow is push-based while Flux is push-pull hybrid

  • Backpressure is implemented via suspending functions

  • Flow has only a single suspending collect method and operators are implemented as extensions

  • Operators are easy to implement thanks to Coroutines

  • Extensions allow adding custom operators to Flow

  • Collect operations are suspending functions

  • map operator supports asynchronous operation (no need for flatMap) since it takes a suspending function parameter

阅读有关 Going Reactive with Spring, Coroutines and Kotlin Flow 的博客文章以获得更多详细信息,包括如何使用 Coroutines 并发运行代码。

Read this blog post about Going Reactive with Spring, Coroutines and Kotlin Flow for more details, including how to run code concurrently with Coroutines.

Repositories

以下是协程存储库的一个示例:

Here is an example of a Coroutines repository:

interface CoroutineRepository : CoroutineCrudRepository<User, String> {

    suspend fun findOne(id: String): User

    fun findByFirstname(firstname: String): Flow<User>

    suspend fun findAllByFirstname(id: String): List<User>
}

协程存储库建立在响应式存储库上,以通过 Kotlin 的协程公开非阻塞数据访问本质。协程存储库上的方法可以由查询方法或自定义实现支持。如果自定义方法为 suspend,调用自定义实现方法会将协程调用传播到实际实现方法,而不要求实现方法返回响应式类型,如 MonoFlux

Coroutines repositories are built on reactive repositories to expose the non-blocking nature of data access through Kotlin’s Coroutines. Methods on a Coroutines repository can be backed either by a query method or a custom implementation. Invoking a custom implementation method propagates the Coroutines invocation to the actual implementation method if the custom method is suspend-able without requiring the implementation method to return a reactive type such as Mono or Flux.

请注意,根据方法声明,协程上下文可能可用或不可用。要保留对上下文的访问,请使用 suspend 声明你的方法或返回能启用上下文传播的类型,如 Flow

Note that depending on the method declaration the coroutine context may or may not be available. To retain access to the context, either declare your method using suspend or return a type that enables context propagation such as Flow.

  • suspend fun findOne(id: String): User: Retrieve the data once and synchronously by suspending.

  • fun findByFirstname(firstname: String): Flow<User>: Retrieve a stream of data. The Flow is created eagerly while data is fetched upon Flow interaction (Flow.collect(…)).

  • fun getUser(): User: Retrieve data once blocking the thread and without context propagation. This should be avoided.

只有当存储库扩展 CoroutineCrudRepository 接口时,才会发现协程存储库。

Coroutines repositories are only discovered when the repository extends the CoroutineCrudRepository interface.