【发布时间】:2020-02-21 19:44:58
【问题描述】:
我正在用 Kotlin 编写 Spring Boot Rest Service。我想使用协程作为 Webflux 的替代方案来实现非阻塞异步行为。我正在使用 Spring Boot 2.1,并且知道我无法实现真正的非阻塞行为,因为我在 Controller 阻塞。不过,在 Spring Boot 2.2 普遍可用之前,我暂时可以接受。
我的应用是三层的,即Controller->Service->Repository。在存储库中,我正在调用其他服务,即网络调用,并将该方法标记为挂起。
我想确保这是否是正确的方法,此外,在ResourceService 中调用挂起乐趣会阻塞调用者线程吗?
在阅读 Roman Elizarov 的 https://medium.com/@elizarov/blocking-threads-suspending-coroutines-d33e11bf4761 之后,我不确定是否应该将 withContext 与我的所有暂停功能一起使用?
package my.springbootapp
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.asCoroutineDispatcher
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext
import mu.KotlinLogging
import org.springframework.boot.SpringApplication
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.stereotype.Repository
import org.springframework.stereotype.Service
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PathVariable
import org.springframework.web.bind.annotation.RestController
import java.util.concurrent.Executors
val logger = KotlinLogging.logger { }
@SpringBootApplication
class App
fun main(args: Array<String>) {
SpringApplication.run(App::class.java, *args)
}
@RestController
class Controller(private val resourceService: ResourceService) {
private val dispatcher = Executors.newFixedThreadPool(5).asCoroutineDispatcher()
@GetMapping("/resource/{id}")
fun getResource(@PathVariable("id") id: String) = runBlocking(dispatcher) {
resourceService.get(id).also { logger.info { Thread.currentThread().name + "Returning $it" } }
}
}
@Service
class ResourceService(private val networkResourceRepository: NetworkResourceRepository) {
suspend fun get(id: String): Resource {
logger.info { Thread.currentThread().name + "Getting resource" }
return networkResourceRepository.get(id)
}
}
@Repository
class NetworkResourceRepository {
suspend fun get(id: String): Resource = withContext(Dispatchers.IO) {
logger.info { Thread.currentThread().name + "Getting resource from n/w" }
//IO operation
Resource("resource data")
}
}
data class Resource(val data: String)
【问题讨论】:
-
“但是,在 Spring Boot 2.2 普遍可用之前,我暂时可以接受。” ----> Spring Boot 2.2 上周发布了 GA,所以试试吧。这是一种更好的体验。
-
从您的端点中删除
runBlocking。无论如何,SpringBoot 中的每个请求都在单独的线程中处理。您的ResourceService不应公开挂起的功能。在内部制作协程,但对外界隐藏它们。
标签: spring-boot kotlin kotlin-coroutines