Spring WebFlux is the reactive alternative to Spring MVC. Instead of one thread per request, it uses a small event loop to handle many concurrent connections — ideal for I/O-bound services that fan out to other systems.
Mono and Flux
Reactive types represent asynchronous sequences. A Mono emits zero or one
item; a Flux emits zero to many.
@Service
public class UserService {
private final UserRepository repository;
public Mono<User> findById(String id) {
return repository.findById(id);
}
public Flux<User> findActive() {
return repository.findByActiveTrue();
}
}Composing without blocking
The golden rule: never call .block() inside a reactive pipeline. Chain
operations instead so the event loop stays free.
public Mono<Receipt> checkout(String userId) {
return userService.findById(userId)
.flatMap(user -> paymentClient.charge(user.balance()))
.map(Receipt::from)
.timeout(Duration.ofSeconds(3));
}Functional endpoints
WebFlux supports annotated controllers, but it also offers a functional routing style that some teams prefer.
@Bean
public RouterFunction<ServerResponse> routes(UserHandler handler) {
return route()
.GET("/api/users/{id}", handler::getUser)
.GET("/api/users", handler::listUsers)
.build();
}When to use it
WebFlux is not automatically faster. It shines when:
- You handle many concurrent, I/O-bound requests.
- Your dependencies (DB driver, HTTP client) are also non-blocking.
- Back-pressure matters — for example, streaming large datasets.
For a typical CRUD app with blocking JDBC, plain Spring MVC is simpler and performs just as well. Choose reactive deliberately, not by default.