WebFlux에서 Controller의 요청처리 과정 (Mono 실행 시점)
WebFlux에서 Mono.just() 를 사용해 기본적인 Controller를 구현했다.
@GetMapping("/mono")
fun mono(): Mono<String> {
logger.log("print 1")
val m: Mono<String> = Mono.just(generateHello())
.doOnNext { logger.log("doOnNext() => $it") }
.log()
logger.log("print 2")
return m
}
fun generateHello(): String {
logger.log("method generateHello()")
return "Hello Mono"
}
* 위 소스에서 logger.log()는 Slf4j Logger를 재정의한 출력 함수이다.
* Mono.log() 는 Publisher와 Subscriber의 기본 동작인 onSubscribe(), onNext(), onComplete() 등의 과정들을 출력하는 함수(Operator)이다.
* Mono 는 기본적으로 데이터를 1개 가지고 있기 때문에 onNext()를 한번만 호출, 그 다음 바로 onComplete()를 호출한다.
WebFlux가 아닌 Web MVC 개념으로 생각하면 위의 mono() 함수가 실행될 때 콘솔에 출력되는 형태를 아래와 같이 예상할 것이다.
print 1
method generateHello()
doOnNext() => Hello Webflux
print 2
하지만 실제 출력 결과는 아래와 같다. ( | 로 시작하는 라인은 log()함수에서 출력함)
즉, Mono 로직은 어떤 라인에 작성되어 있는지 무관하게 실제로 가장 마지막에 실행이 되었다는 것을 알 수 있다.
WebFlux는 Controller에서 반환된 Mono 객체로 subscribe() 를 실행하기 때문에, 함수가 끝난 뒤 Mono 로직이 실행된다.
만약 generateHello() 함수를 Mono가 실행되는 시점에 실행하고 싶다면 fromSupplier() 사용할 수 있다. (Mono 로직은 여전히 메소드가 끝난 후 실행된다.)
// Mono.just 수정
val m: Mono<String> = Mono.fromSupplier {generateHello()}
.doOnNext { logger.log("doOnNext() => $it") }
.log()
코드를 위와 같이 수정하면 method generateHello() 메세지 출력 위치가 변경된 것을 확인할 수 있다.
불필요한 출력 함수를 제거하고 맨 위의 소스코드에서 m.subscribe()를 추가해보았다.
@GetMapping("/mono")
fun mono(): Mono<String> {
val m: Mono<String> = Mono.just("Hello Mono")
.doOnNext { logger.log("doOnNext() => $it") }
m.subscribe()
return m
}
실행 결과는 doOnNext() => Hello Mono 가 2번 출력될 것이다.
첫번째는 함수 내에서 m.subscribe()를 실행할 때, 두번째는 return m 이후 webflux 라이브러리에서 subscribe()를 실행했을 때.
Mono가 담고있는 객체 꺼내기
block() 함수를 사용하면 Mono가 담고있는 객체를 꺼낼 수 있다.
요청을 처리하고 나서 단순히 결과 객체만 필요하다 싶을 때 사용할 수 있고, block()을 사용하면 위에서 m.subscribe()를 명시한것처럼 함수 내에서 Mono 로직을 수행한다.
아래 예제가 있다.
@GetMapping("/mono")
fun mono(): Mono<String> {
val msg = "Hello Mono"
val m: Mono<String> = Mono.just(msg)
.doOnNext { logger.log("doOnNext() => $it") }
val data = m.block() as String // 위의 Mono chain 실행
logger.log("data => $data")
logger.log("data obj is same with msg ? => ${data.equals(msg)}")
// return 후에 Mono chain 한번 더 실행
return m
}
doOnNext() => Hello Mono 가 총 두번 실행되었고 중간에 logger.log()로 출력한 메세지가 있다.
이를 통해 block() 함수를 요청하면 Mono chain이 실행된다는 것을 확인할 수 있다.
* 가능한 block()은 직접 호출하지 않는 것이 좋다고 한다.
* WebFlux 내부에서 이미 정의되어 있을테니 가능한 Mono에 데이터를 담아, Mono만 사용해서 return 하도록 한다.
'생계유지형 개발자 > Reactive Programming' 카테고리의 다른 글
[리액티브 프로그래밍] 토비의 WebFlux, Mono, Flux 강의 (0) | 2021.03.17 |
---|---|
[리액티브 프로그래밍] User Thread, Daemon Thread의 차이점 (0) | 2021.03.16 |
[리액티브 프로그래밍] 리액티브 프로그래밍이란 (0) | 2021.01.29 |