WebClient의 .body(...)와 .bodyValue(...)의 차이는 "비동기 객체인지 아닌지", 즉 Reactive 타입인지 아닌지에 따라 나뉜다.
bodyValue(value: T)
즉시 사용할 수 있는 일반 객체일 때 사용
내부적으로 Mono.just(value)로 감싼 것과 같음
비동기 처리를 하지 않고, 즉시 요청에 넣음
val person = Person("Kim", 30)
webClient.post()
.uri("/person")
.bodyValue(person) // 바로 쓸 수 있는 객체
.retrieve()
.awaitBody<Unit>()
body(publisher: Publisher<T>)
Mono<T>, Flow<T>, Deferred<T> 등 비동기 데이터 소스를 처리할 때 사용
데이터가 나중에 준비되면, 그걸 사용해 본문을 구성함
.body(...)는 데이터를 Publisher 또는 Coroutine 타입으로 받는다
val deferredPerson: Deferred<Person> = async {
getPersonFromDB() // 비동기 DB 조회
}
webClient.post()
.uri("/person")
.body(deferredPerson) // 나중에 준비될 값
.retrieve()
.awaitBody<Unit>()
- val person = Person(...) → .bodyValue(person)
- val person: Deferred<Person> → .body(person)
- val personMono: Mono<Person> → .body(personMono)
- val personFlow: Flow<Person> → .body(personFlow)
Flow, Mono, Deferred 간 차이
모두 비동기 데이터를 다루는 방식이지만, 각각의 목적과 특성이 다르다.
Deferred<T> – 단일 값 비동기 작업
- async { ... }로 생성
- 비동기적으로 계산된 하나의 값을 나중에 받을 수 있음
- Kotlin Coroutine에서 제공
- await()를 통해 값을 꺼냄
val deferred: Deferred<String> = async {
delay(1000)
"Hello"
}
val result = deferred.await()
Flow<T> – 여러 값의 비동기 스트림
- flow { emit(...) }로 생성
- 여러 값을 순차적으로 emit (흐름)
- Kotlin Coroutine에서 제공
- collect { ... } 또는 first(), toList() 등으로 사용
val flow: Flow<Int> = flow {
emit(1)
emit(2)
emit(3)
}
flow.collect { println(it) }
Mono<T> – 단일 값의 Reactive 타입
- Project Reactor에서 제공 (Spring WebFlux 기반)
- Mono.just(value) 또는 Mono.fromCallable { ... }
- subscribe { ... }, awaitSingle() (Kotlin에서는)
val mono: Mono<String> = Mono.just("Hello")
mono.subscribe { println(it) }
Deferred | Flow | Mono | |
프레임워크 | Kotlin Coroutines | Kotlin Coroutines | Reactor (Spring) |
데이터 수 | 단일 값 | 여러 값 | 단일 값 |
취소/중단 | 지원 | 지원 | 지원 (reactive 방식) |
사용 예 | 비동기 계산 결과 | 스트리밍 데이터 | WebClient 비동기 요청 결과 |
시간이 걸리는 작업을 백그라운드에서 처리하고, 나중에 단일 결과를 사용하고 싶을 때 | 여러 데이터를 지연 처리, 스트리밍, 또는 이벤트처럼 다룰 때 | Spring WebFlux 등 리액티브 환경에서 단일 비동기 값을 처리할 때 | |
WebClient 사용 | .body(deferred) | .body(flow) | .body(mono) |
예를 들어 WebClient에 쓸 때
// Deferred 사용
val dataDeferred: Deferred<Data> = ...
webClient.post().body(dataDeferred) ...
// Flow 사용
val dataFlow: Flow<Data> = ...
webClient.post().body(dataFlow) ...
// Mono 사용 (Java 기반 Reactive)
val dataMono: Mono<Data> = ...
webClient.post().body(dataMono) ...
필요하다면 Mono ↔ Deferred 변환, Flow ↔ Flux 변환도 가능하다.
Kotlin에서는 주로 Deferred와 Flow, Java 기반에서는 Mono, Flux를 사용한다.
'【 개발 이야기 】' 카테고리의 다른 글
[git] rebase 이해하기 (0) | 2025.06.02 |
---|---|
볼만한 개발 블로그.. (0) | 2025.05.30 |
[spring] web client 공식 문서 번역 (1) | 2025.05.08 |
[kotlin] inline 함수란 뭘까... (1) | 2025.04.29 |
[보안] Base64 인코딩과 iv (0) | 2025.04.25 |