Publisher를 구현한 두 핵심 타입 — 1단계의 Publisher/Subscriber·배압·”구독 전엔 실행 안 됨” 위에서 동작Flux<T>는 표준 Publisher<T> — 0~N개 아이템을 비동기로 방출하고, 선택적으로 완료(onComplete) 또는 에러(onError) 로 종료Subscriber의 onNext/onComplete/onError 호출로 이어짐Mono<T>는 특화된 Publisher<T> — onNext로 최대 1개를 방출한 뒤 곧바로 onComplete(값이 있든 없든 성공), 또는 onError 1회(실패)
onNext 직후 즉시 onComplete를 호출onNext + onError 조합은 금지Flux 연산자의 부분집합만 제공 — 0..1에 의미 있는 것만 (예: count처럼 다개수 전제 연산은 없음)
Mono.concatWith(Publisher) → Flux, Mono.then(Mono) → MonoMono<Void> — Runnable처럼 “끝났다”만 알림Flux<HttpResponse>보다 Mono<HttpResponse>가 적합| Flux | Mono | |
|---|---|---|
| 아이템 수 | 0..N | 0..1 |
| 정상 종료 | onNext* 후 onComplete | onNext 0~1회 후 onComplete |
| 연산자 | 전체 | 0..1에 맞는 부분집합 |
| 대표 용도 | 목록·스트림·이벤트 | 단건 조회·저장 결과·완료 신호(Mono<Void>) |
onNext 값| = onComplete(정상 종료), X = onError(에러 종료) Flux.just("foo", "bar", "foobar"); // 알려진 값들을 나열
Flux.fromIterable(list); // Iterable(List 등)에서
Flux.fromArray(array); // 배열에서
Flux.range(5, 3); // 5, 6, 7 — (시작값, 개수)
Flux.empty(); // 값 없이 즉시 완료
Flux.error(new RuntimeException()); // 즉시 에러로 종료
Mono.just("foo");
Mono.justOrEmpty(nullable); // null이면 빈 Mono
Mono.empty(); // 값 없이 완료 (Mono<Void> 등)
Mono.error(new IllegalStateException());
generate/create/push (3단계 이후)subscribe() 호출 전엔 아무 일도 일어나지 않는다 → subscribe가 시퀀스를 트리거 subscribe(); // 구독만 하고 시퀀스 트리거
subscribe(onNext); // 각 값 처리
subscribe(onNext, onError); // + 에러에 반응
subscribe(onNext, onError, onComplete); // + 정상 완료 시 실행 (onComplete은 Runnable — 값 없음)
subscribe(onNext, onError, onComplete, subscription); // + Subscription을 받아 수요(request) 직접 제어
Flux.range(1, 4)
.map(i -> {
if (i <= 3) return i;
throw new RuntimeException("Got to 4");
})
.subscribe(
i -> System.out.println(i), // onNext: 1, 2, 3
err -> System.err.println("Error: " + err), // onError: i=4에서 예외 → 시퀀스 종료
() -> System.out.println("Done")); // onComplete: 에러로 끝나면 호출되지 않음
BaseSubscriber를 확장해 hookOnSubscribe에서 request(n)을 직접 호출하는 편이 안전 (1단계 request(n)과 연결)subscribe는 모두 Disposable을 반환 → dispose()를 호출하면 구독이 취소됨Subscription.cancel()과 연결
Disposable disposable = source.subscribe(...);
disposable.dispose(); // 정리 시점에 구독 취소
just/fromIterable/range 등 기본 팩토리는 cold)share()/publish() 등 별도 연산자 필요 (3단계 이후)