Spring Webflux
WebFlux is non-blocking, asynchronous web framework based on project Reactor.
WebFlux Core Architecture & Components
Spring WebFlux is built around a non-blocking handler mapping and processing pipeline designed to handle high concurrency with a low footprint of threads.
1. WebFlux Core Components
The following PlantUML diagram shows the main execution contracts of the Spring WebFlux framework and how they interact to process requests:
interface HttpHandler {
+ Mono<Void> handle(ServerHttpRequest request, ServerHttpResponse response)
}
interface WebHandler {
+ Mono<Void> handle(ServerWebExchange exchange)
}
class DispatcherHandler implements WebHandler {
- List<HandlerMapping> handlerMappings
- List<HandlerAdapter> handlerAdapters
- List<HandlerResultHandler> handlerResultHandlers
+ Mono<Void> handle(ServerWebExchange exchange)
}
interface HandlerMapping {
+ Mono<Object> getHandler(ServerWebExchange exchange)
}
interface HandlerAdapter {
+ boolean supports(Object handler)
+ Mono<HandlerResult> handle(ServerWebExchange exchange, Object handler)
}
interface HandlerResultHandler {
+ boolean supports(HandlerResult result)
+ Mono<Void> handleResult(ServerWebExchange exchange, HandlerResult result)
}
class ServerWebExchange {
+ ServerHttpRequest getRequest()
+ ServerHttpResponse getResponse()
+ Mono<WebSession> getSession()
+ Mono<Principal> getPrincipal()
}
DispatcherHandler --> HandlerMapping : 1. resolves handler
DispatcherHandler --> HandlerAdapter : 2. executes handler
DispatcherHandler --> HandlerResultHandler : 3. processes execution result
Roles of Core Classes:
HttpHandler: The lowest-level abstraction that adapts server-specific request/response models (e.g. Netty, Undertow, or Servlets) into the WebFlux-independentServerHttpRequestandServerHttpResponse.DispatcherHandler: The main orchestration component (acting like Spring MVC’sDispatcherServlet). It coordinates request routing, execution, and result serialization.HandlerMapping: Maps incoming requests to an execution target (such as a@Controllerhandler method or a router function).HandlerAdapter: Adapts execution invocations for different types of handlers.HandlerResultHandler: Processes the returned result from handler execution (e.g., serializing aMono<User>orFlux<Event>response body to JSON).
2. Request Processing Flow
[Inbound Netty Request]
│
▼
┌───────────────┐
│ HttpHandler │ (Adapts Netty requests to ServerWebExchange)
└───────┬───────┘
│
▼
┌───────────────┐
│ WebHandler │
│ (Dispatcher) │ ───► Mapping: Resolves mapping to controllers or router functions
└───────┬───────┘
│
▼
┌───────────────┐
│ HandlerAdapter│ ───► Execution: Invokes target endpoint returning Mono<HandlerResult>
└───────┬───────┘
│
▼
┌───────────────┐
│ ResultHandler │ ───► Serialization: Writes response bytes back asynchronously
└───────────────┘
3. Programming Models & Examples
Spring WebFlux supports two programming models: Annotated Controllers and Functional Endpoints.
A. Annotated Controller Style
This style is very similar to standard Spring MVC but leverages Project Reactor types (Mono and Flux) to handle threads asynchronously:
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Mono;
@RestController
@RequestMapping("/api/users")
public class UserController {
private final UserService userService;
public UserController(UserService userService) {
this.userService = userService;
}
@GetMapping("/{id}")
public Mono<User> getUserById(@PathVariable String id) {
// Non-blocking query yielding a Mono wrapper.
// The event loop threads are released while waiting for the query completion.
return userService.findUserById(id);
}
}
B. Functional Endpoints Style
A functional, routing-oriented API where routing configuration is separated from the execution logic:
1. Routing Definition (RouterFunction)
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.ServerResponse;
import static org.springframework.web.reactive.function.server.RequestPredicates.GET;
import static org.springframework.web.reactive.function.server.RouterFunctions.route;
@Configuration
public class UserRouter {
@Bean
public RouterFunction<ServerResponse> userRoutes(UserHandler handler) {
return route(GET("/api/users/{id}"), handler::getUserById);
}
}
2. Request Handling (HandlerFunction)
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;
import reactor.core.publisher.Mono;
@Component
public class UserHandler {
private final UserService userService;
public UserHandler(UserService userService) {
this.userService = userService;
}
public Mono<ServerResponse> getUserById(ServerRequest request) {
String id = request.pathVariable("id");
return userService.findUserById(id)
.flatMap(user -> ServerResponse.ok().bodyValue(user))
.switchIfEmpty(ServerResponse.notFound().build());
}
}