Lesson 38 / 38

Reactive Programming Intro

See the problem reactive streams solve — blocking threads under load — and read a minimal non-blocking WebFlux endpoint built on Mono and Flux.

The problem: one thread per request

A traditional (servlet) request handler blocks its thread while waiting on a slow downstream call — under heavy load you run out of threads even though the CPU is idle, just waiting on I/O. Reactive programming (Reactive Streams / Project Reactor) instead registers a callback and frees the thread to serve other work while waiting.

Mono and Flux

Mono<T> represents zero-or-one async value, Flux<T> zero-to-many — both are lazy: nothing runs until something subscribes. Spring WebFlux controllers return them directly instead of blocking for the result.

@RestController
class UserController {
    private final WebClient client;

    @GetMapping("/users/{id}")
    Mono<User> get(@PathVariable String id) {
        return client.get()
            .uri("/legacy-users/{id}", id)
            .retrieve()
            .bodyToMono(User.class);   // non-blocking
    }
}

When it's (not) worth it

Reactive shines for high-concurrency I/O-bound services (gateways, streaming, fan-out to many backends). For typical CRUD apps under modest load, plain blocking code on virtual threads (Java 21+) gives similar scalability with far simpler, easier-to-debug code — reach for reactive only when you've measured a real need.