Mono 고급 정리 - zip, fromCallable, block까지 실전 활용 정리
2025. 5. 20. 22:21ㆍBack-End/Spring-Boot
반응형
이전 글에서 Mono의 기본 생성 방식과 연산자들 (flatMap, map, switchIfEmpty 등)을 정리했었다.
이번에는 한 단계 더 나아가서, 실무에서 자주 마주치는 상황에서 어떻게 Mono를 응용할 수 있을지 다뤄보자.
1. Mono.zip() - 여러 Mono를 병렬로 실행하고 결과를 합칠 때
zip()은 두 개 이상의 Mono를 동시에 실행해서, 결과를 묶어서 처리할 수 있게 해준다.
(모든 Mono가 완료되기 전까지는 실행되지 않음)
예제: 사용자 정보와 포인트 정보를 동시에 가져오기
Mono<User> userMono = userRepository.findById("123");
Mono<Point> pointMono = pointService.getPointByUserId("123");
Mono<Tuple2<User, Point>> zipped = Mono.zip(userMono, pointMono);
zipped.map(tuple -> {
User user = tuple.getT1();
Point point = tuple.getT2();
return new UserResponse(user, point);
});
Mono.zip은 성능 측면에서 유리할 때가 많다. (병렬 실행 구조)
2. Mono.fromCallable() - 블로킹 코드도 Mono로 감싸서 비동기로 처리하기
예를 들어 파일 읽기, 외부 라이브러리 호출처럼 블로킹 작업이 필요할 때 사용한다.
Mono<String> fileContentMono = Mono.fromCallable(() -> {
// 블로킹 코드
return Files.readString(Path.of("sample.txt"));
}).subscribeOn(Schedulers.boundedElastic());
반드시 .subscribeOn()과 함께 사용하자.
Reactor는 기본적으로 non-blocking 쓰레드만 사용하므로, 블로킹 코드를 별도 쓰레드로 넘겨야 한다.
3. subscribe() vs block() - 차이를 명확히 알아두자
이 둘은 Mono의 실행 시점과 관련이 있다.
subscribe()
- 비동기적으로 실행
- 값이 오면 콜백으로 처리
- Spring WebFlux에서는 보통 프레임워크가 자동으로 subscribe 해줌
Mono.just("hello")
.subscribe(value -> System.out.println("값: " + value));
block()
- 현재 쓰레드를 블로킹하면서 값이 나올 때까지 기다림
- 테스트 코드나 초기 부트스트랩 코드에서만 사용하는 것이 좋음
String result = Mono.just("hello").block(); // 즉시 결과가 필요할 때
실서비스 코드에서 block()을 쓰는 순간, WebFlux의 비동기 이점이 사라진다.
꼭 필요한 경우가 아니라면 피하자.
4. Mono를 반환하는 서비스 계층 작성 예시
public Mono<UserDto> getUserWithPoint(String userId) {
return Mono.zip(
userRepository.findById(userId),
pointService.getPointByUserId(userId)
)
.map(tuple -> {
User user = tuple.getT1();
Point point = tuple.getT2();
return new UserDto(user, point);
});
}
이처럼 여러 비동기 작업을 묶어 최종 결과를 만들어내는 게 Mono의 핵심 활용 방식이다.
5. 예외 처리 - onErrorResume, onErrorReturn
onErrorResume
Mono.just("value")
.flatMap(this::dangerousOperation)
.onErrorResume(e -> {
log.warn("에러 발생", e);
return Mono.just("기본값");
});
onErrorReturn
Mono.just("value")
.flatMap(this::dangerousOperation)
.onErrorReturn("기본값");
onErrorResume은 대체 흐름을 Mono로 지정할 수 있어 더 유연하다.
마무리
Spring WebFlux에서 Mono는 단순한 비동기 데이터 컨테이너를 넘어서,
다양한 상황에 맞게 데이터를 결합하고, 처리 흐름을 제어하는 핵심 도구가 된다.
- 여러 비동기 결과를 묶을 땐 zip()
- 블로킹 코드는 fromCallable()로 감싸고 subscribeOn() 붙이기
- 절대 block() 남용하지 않기
반응형
'Back-End > Spring-Boot' 카테고리의 다른 글
| 스프링 부트 GC 로그 해석 실전 — Metadata GC Threshold로 Full GC가 길어질 때 (4) | 2025.08.12 |
|---|---|
| Spring WebFlux의 Mono (0) | 2025.05.20 |
| DTO ↔ Entity 변환에 대한 고민과 MapStruct (0) | 2025.03.16 |
| JPA에서 JPQL 사용하는 법 (0) | 2025.03.16 |
| 파라미터 포맷 변환(String -> LocalDateTime) (0) | 2025.03.13 |