Mono<T> — publisher phát ra 0 hoặc 1 phần tử (như Optional nhưng async).Flux<T> — publisher phát ra 0 đến N phần tử (như Stream nhưng async, có thể vô tận).
Cả 2 đều lazy — chỉ chạy khi có subscriber (subscribe(), hoặc framework subscribe).
// Mono — 1 user
Mono<User> findById(Long id) { return userRepo.findById(id); }
// Flux — nhiều record
Flux<Order> recentOrders() {
return orderRepo.findAllByDateAfter(yesterday())
.filter(o -> o.getTotal().compareTo(BigDecimal.TEN) > 0)
.map(o -> enrich(o));
}Backpressure: consumer báo producer "tôi chỉ nhận X item/giây" → tránh OOM khi producer nhanh hơn consumer.
Flux.fromStream(bigDbStream)
.onBackpressureBuffer(1000) // buffer 1000 item, sau đó block producer
// hoặc .onBackpressureDrop() // drop nếu consumer chậm
.subscribe(this::process);Stream 1M record từ DB không backpressure → load hết vào memory → OOM.
Operator chính: map, flatMap, filter, zip, merge, delayElements, retry — chain async op kiểu declarative.
Lưu ý 2026: với Virtual Threads (Java 21), Spring MVC + blocking I/O đã đạt concurrency tương đương WebFlux — chỉ dùng WebFlux khi cần backpressure thực sự (streaming, SSE) hoặc fully reactive stack.
Mono<T> — publisher emitting 0 or 1 item (like Optional but async).Flux<T> — publisher emitting 0 to N items (like Stream but async, potentially infinite).
Both are lazy — they run only when subscribed (subscribe(), or via framework subscription).
// Mono — one user
Mono<User> findById(Long id) { return userRepo.findById(id); }
// Flux — many records
Flux<Order> recentOrders() {
return orderRepo.findAllByDateAfter(yesterday())
.filter(o -> o.getTotal().compareTo(BigDecimal.TEN) > 0)
.map(o -> enrich(o));
}Backpressure: the consumer signals the producer "I can handle X items/second" → prevents OOM when the producer outpaces the consumer.
Flux.fromStream(bigDbStream)
.onBackpressureBuffer(1000) // buffer 1000 items, then block the producer
// or .onBackpressureDrop() // drop if consumer is slow
.subscribe(this::process);Streaming 1M records from a DB without backpressure → loads all into memory → OOM.
Key operators: map, flatMap, filter, zip, merge, delayElements, retry — declarative chaining of async ops.
2026 note: with Virtual Threads (Java 21), Spring MVC + blocking I/O achieves comparable concurrency to WebFlux — only choose WebFlux when you genuinely need backpressure (streaming, SSE) or a fully reactive stack.