728x90
스프링 WebFlux 코루틴 지원
- 프로젝트 리액터 기반의 리액티브 프로그래밍은 비동기/Non-Blocking의 단점인 콜백 헬 문제를 순차적으로 동작하는 연산자를 통해 해결했다.
- 기존 함수형 패러다임에 익숙하거나, 리액터의 다양한 연산자에 대한 학습이 부담이 없다면 리액티브 프로그래밍은 비동기/Non-Blocking 코드 작성 시 매우 좋은 솔루션이나, 러닝 커브가 너무 높다.
- 안드로이드도 최근에 RxJava에서 코루틴 기반으로 작성하는 코드가 늘어나고 있으며, 서버 측에서도 코루틴을 도입하는 사례가 많아지고 있다.
코루틴
suspend fun combineApi() = coroutineScope {
val response1 = async { getApi1() }
val response2 = async { getApi2() }
return ApiResult (
response1.await()
response2.await()
)
}
- 코루틴은 코틀린에서 비동기/Non-Blocking 프로그래밍을 명령형 스타일로 작성할 수 있도록 도와주는 라이브러리이다
- 코루틴은 멀티 플랫폼을 지원하며, 코틀린을 사용하는 안드로이드, 서버 등 여러 환경에서 사용할 수 있다.
- 코루틴은 일시 중단 가능한 함수(Suspend) 를 통해 스레드가 실행을 잠시 중단 했다가 중단한 시점부터 다시 resume 할 수 있다.
스프링 WebFlux 코루틴 지원
dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:${version}")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-reactor:${version}")
}
- 해당 의존성을 추가하면 코루틴을 사용할 수 있다.
- 스프링 WebFlux 공식문서의 코틀린 예제들 또한 모두 코루틴 기반의 예제를 소개하고 있다.
- 스프링 MVC, 스프링 WebFlux 모두 코루틴을 지원하며, 의존성만 추가하면 바로 사용 가능하다.
리액티브 -> 코루틴
//Mono → suspend
fun handler(): Mono<Void> -> suspend fun handler()
//Flux → Flow
fun handler(): Flux<T> -> fun handler(): Flow<T>
- Mono -> Suspend 함수로 변환된다.
- Flux -> Flow로 변환된다.
코루틴 예시
Controller
@RestController
class UserController(
private val userService : UserService,
private val userDetailService: UserDetailService
) {
@GetMapping("/{id}")
suspend fun get(@PathVariable id: Long) : User {
return userService.getById(id)
}
@GetMapping("/users")
suspend fun gets() = withContext(Dispatchers.IO) {
val usersDeffered = async { userService.gets() }
val userDetailsDeffered = async { userDetailService.gets() }
return UserList(usersDeffered.await(), userDetailsDeffered.await())
}
}
- suspend 키워드를 통해 해당 함수가 코루틴으로 동작하는지 파악할 수 있다.
- async 블락을 이용하여 해당 함수를 비동기로, await를 통해 해당 값을 받아서 처리할 수 있도록 동작시킬 수 있다.
WebClient
val client = WebClient.create("https://example.org")
val result = client.get()
.uri("/persons/{id}", id)
.retrieve()
.awaitBody<Person>()
- 기존 리액티브 코드를 코루틴으로 변경하기 위해서는 await~ 로 시작하는 확장 함수를 사용하면 된다.
- 사용 시 즉시 코루틴으로 변환할 수 있다.
Spring Data R2DBC의 ReactiveCrudRepository에서 코루틴 적용
interface ContentReactiveRepository : ReactiveCrudRepository<Content, Long> {
fun findByUserId(userId: Long) : Mono<Content>
fun findAllByUserId(userId: Long): Flux<Content>
}
class ContentService (
val repository : ContentReactiveRepository
) {
fun findByUserIdMono(userId: Long) : Mono<Content> {
return repository.findByUserId(userId)
}
suspend findByUserId (userId: Long) : Content {
return repository.findByUserId(userId).awaitSingle()
}
}
- AwaitSing 함수를 사용하여, 해당 값을 Mono와 같은 것으로 감싸지 않아도 된다.
CoroutineCrudRepository를 사용하면 await~ 함수 제거 가능
interface ContentCouroutineRepository : CoroutineCrudRepository<Content, Long> {
suspend fun findByUserId(userId:Long) : Content?
fun findAllByUserId(userId: Long): Flow<Content>
}
class ContentService (
val repository : ContentCouroutineRepository
) {
suspend findByUserId (userId: Long) : Content {
return repository.findByUserId(userId)
}
}
}
- CoroutineCrudRepository를 활용하여, Flux -> Flow, Mono -> Suspend를 반환하도록 변경할 수 있다.
728x90
'실무 프로젝트로 배우는 Kotlin & Spring > 스프링 WebFlux 이해하기' 카테고리의 다른 글
| 코루틴 기초 (0) | 2022.12.11 |
|---|---|
| 스프링 데이터 R2DBC (0) | 2022.12.11 |
| 웹클라이언트 (0) | 2022.12.11 |
| 애노테이션 컨트롤러 (0) | 2022.12.11 |
| 함수형 엔드포인트 (0) | 2022.12.02 |