Understanding Spring WebFlux’s DispatcherHandler and Request Flow
This article explains how Spring WebFlux uses the DispatcherHandler, HandlerMapping, HandlerAdapter, and various HandlerResultHandlers to process requests, configure special beans, and manage exceptions in a reactive backend environment.
Overview
Similar to Spring MVC, Spring WebFlux is built around the front‑controller pattern. Its core handler, WebHandler , is implemented by DispatcherHandler , which provides shared algorithms for request processing while delegating actual work to configurable components, allowing flexible workflows.
Special Beans
DispatcherHandler discovers required delegate beans from the Spring context. It is itself a bean and implements ApplicationContextAware to access its context. When a bean named webHandler is declared, WebHttpHandlerBuilder finds it and assembles the request‑handling chain.
WebFlux Configuration
Typical WebFlux applications declare beans such as:
Bean named webHandler of type DispatcherHandler
WebFilter and WebExceptionHandler
Special DispatcherHandler bean
Other supporting beans
These beans are supplied to WebHttpHandlerBuilder to build the handling chain, as shown in the example below.
public class HttpHandlerAutoConfiguration {
@Configuration(proxyBeanMethods = false)
public static class AnnotationConfig {
@Bean
public HttpHandler httpHandler(ObjectProvider<WebFluxProperties> propsProvider) {
// applicationContext method collects WebFilter and WebExceptionHandler
// build method constructs HttpWebHandlerAdapter (implements HttpHandler) that wraps them
HttpHandler httpHandler = WebHttpHandlerBuilder.applicationContext(this.applicationContext).build();
WebFluxProperties properties = propsProvider.getIfAvailable();
if (properties != null && StringUtils.hasText(properties.getBasePath())) {
Map<String, HttpHandler> handlersMap = Collections.singletonMap(properties.getBasePath(), httpHandler);
return new ContextPathCompositeHandler(handlersMap);
}
return httpHandler;
}
}
}HandlerMapping
HandlerMapping maps a request to a handler based on various criteria (e.g., @RequestMapping annotations or RouterFunction beans). The first matching mapping is used.
HandlerAdapter
After a handler is found, a suitable HandlerAdapter invokes it and produces a HandlerResult . The adapter shields DispatcherHandler from the details of how the handler is invoked.
HandlerResultHandler
The HandlerResult is passed to a HandlerResultHandler to complete the response, either by writing directly or by rendering a view. Common implementations include:
ResponseEntityResultHandler – handles ResponseEntity returned from @Controller methods.
ServerResponseResultHandler – handles ServerResponse from functional endpoints.
ResponseBodyResultHandler – handles values from @ResponseBody or @RestController methods.
ViewResolutionResultHandler – resolves CharSequence, view names, models, etc.
Request Handling
Each HandlerMapping tries to find a matching handler; the first match wins.
If a handler is found, the appropriate HandlerAdapter executes it, producing a HandlerResult .
The HandlerResult is then processed by a HandlerResultHandler to generate the final response.
Exception Handling
If a handler fails or a HandlerResultHandler cannot process the result, an error function can modify the response before any data is written. In WebFlux, @ExceptionHandler methods in @Controller classes are supported via HandlerExceptionResolver , but @ControllerAdvice cannot handle exceptions that occur before a handler is selected; those must be handled by a WebExceptionHandler .
@RestControllerAdvice
public class PackControllerAdvice {
@ExceptionHandler
public ResponseEntity<String> handle(Exception ex) {
ex.printStackTrace();
return ResponseEntity.ok(ex.getMessage() + ", Advice");
}
} @Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class CustomWebExceptionHandler implements WebExceptionHandler {
@Override
public Mono<Void> handle(ServerWebExchange exchange, Throwable ex) {
System.out.println("异常了: " + ex.getMessage());
ServerHttpResponse response = exchange.getResponse();
response.setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR);
response.getHeaders().add("ContentType", "text/html;charset=utf8");
return response.writeWith(Mono.just(exchange.getResponse().bufferFactory().wrap("ERROR".getBytes(Charset.forName("UTF-8")))));
}
}End of article.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Spring Full-Stack Practical Cases
Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
