How Spring WebFlux Handles HTTP Requests: From HttpHandler to DispatcherHandler
This article explains how Spring WebFlux processes HTTP requests by auto‑configuring an HttpHandler, building a chain of WebFilters and exception handlers, delegating through HttpWebHandlerAdapter, and ultimately invoking DispatcherHandler, detailing each component’s role and the flow of request handling.
1 Request Entry HttpHandler
Spring Boot automatically configures an HttpHandler bean via HttpHandlerAutoConfiguration. The core handler class in a WebFlux environment is HttpWebHandlerAdapter.
public class HttpHandlerAutoConfiguration {
@Configuration(proxyBeanMethods = false)
public static class AnnotationConfig {
private final ApplicationContext applicationContext;
public AnnotationConfig(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
@Bean
public HttpHandler httpHandler(ObjectProvider<WebFluxProperties> propsProvider) {
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;
}
}
}The HttpWebHandlerAdapter implements the request entry point:
public class HttpWebHandlerAdapter extends WebHandlerDecorator implements HttpHandler {
public Mono<Void> handle(ServerHttpRequest request, ServerHttpResponse response) {
if (this.forwardedHeaderTransformer != null) {
try {
request = this.forwardedHeaderTransformer.apply(request);
} catch (Throwable ex) {
response.setStatusCode(HttpStatus.BAD_REQUEST);
return response.setComplete();
}
}
ServerWebExchange exchange = createExchange(request, response);
return getDelegate().handle(exchange)
.doOnSuccess(aVoid -> logResponse(exchange))
.onErrorResume(ex -> handleUnresolvedError(exchange, ex))
.then(Mono.defer(response::setComplete));
}
}The getDelegate() method returns the delegate defined in the parent WebHandlerDecorator, which ultimately is an ExceptionHandlingWebHandler instance.
Application Context Refresh
public abstract class AbstractApplicationContext {
public void refresh() throws BeansException, IllegalStateException {
// ...
onRefresh();
// ...
}
}
public class ReactiveWebServerApplicationContext {
protected void onRefresh() {
// ...
createWebServer();
// ...
}
private void createWebServer() {
WebServerManager serverManager = this.serverManager;
if (serverManager == null) {
// this::getHttpHandler obtains the HttpHandler bean
this.serverManager = new WebServerManager(this, webServerFactory, this::getHttpHandler, lazyInit);
}
initPropertySources();
}
protected HttpHandler getHttpHandler() {
String[] beanNames = getBeanFactory().getBeanNamesForType(HttpHandler.class);
return getBeanFactory().getBean(beanNames[0], HttpHandler.class);
}
}WebHandlerDecorator
public class WebHandlerDecorator implements WebHandler {
private final WebHandler delegate;
public WebHandlerDecorator(WebHandler delegate) {
this.delegate = delegate;
}
public WebHandler getDelegate() {
return this.delegate;
}
}WebHttpHandlerBuilder Construction
public final class WebHttpHandlerBuilder {
private final List<WebFilter> filters = new ArrayList<>();
public static WebHttpHandlerBuilder applicationContext(ApplicationContext context) {
WebHttpHandlerBuilder builder = new WebHttpHandlerBuilder(
context.getBean(WEB_HANDLER_BEAN_NAME, WebHandler.class), context);
List<WebFilter> webFilters = context.getBeanProvider(WebFilter.class)
.orderedStream()
.collect(Collectors.toList());
builder.filters(filters -> filters.addAll(webFilters));
List<WebExceptionHandler> exceptionHandlers = context.getBeanProvider(WebExceptionHandler.class)
.orderedStream()
.collect(Collectors.toList());
builder.exceptionHandlers(handlers -> handlers.addAll(exceptionHandlers));
context.getBeanProvider(HttpHandlerDecoratorFactory.class)
.orderedStream()
.forEach(builder::httpHandlerDecorator);
// optional beans omitted for brevity
return builder;
}
public HttpHandler build() {
WebHandler decorated = new FilteringWebHandler(this.webHandler, this.filters);
decorated = new ExceptionHandlingWebHandler(decorated, this.exceptionHandlers);
HttpWebHandlerAdapter adapted = new HttpWebHandlerAdapter(decorated);
return (this.httpHandlerDecorator != null ? this.httpHandlerDecorator.apply(adapted) : adapted);
}
}ExceptionHandlingWebHandler
public class ExceptionHandlingWebHandler extends WebHandlerDecorator {
private final List<WebExceptionHandler> exceptionHandlers;
public Mono<Void> handle(ServerWebExchange exchange) {
Mono<Void> completion;
try {
completion = super.handle(exchange);
} catch (Throwable ex) {
completion = Mono.error(ex);
}
for (WebExceptionHandler handler : this.exceptionHandlers) {
completion = completion.onErrorResume(ex -> handler.handle(exchange, ex));
}
return completion;
}
}FilteringWebHandler
public class FilteringWebHandler extends WebHandlerDecorator {
private final DefaultWebFilterChain chain;
public FilteringWebHandler(WebHandler handler, List<WebFilter> filters) {
super(handler);
this.chain = new DefaultWebFilterChain(handler, filters);
}
@Override
public Mono<Void> handle(ServerWebExchange exchange) {
return this.chain.filter(exchange);
}
}DefaultWebFilterChain
public class DefaultWebFilterChain implements WebFilterChain {
private final List<WebFilter> allFilters;
private final WebFilter currentFilter;
private final WebHandler handler;
public DefaultWebFilterChain(WebHandler handler, List<WebFilter> filters) {
Assert.notNull(handler, "WebHandler is required");
this.allFilters = Collections.unmodifiableList(filters);
this.handler = handler;
DefaultWebFilterChain chain = initChain(filters, handler);
this.currentFilter = chain.currentFilter;
this.chain = chain.chain;
}
private static DefaultWebFilterChain initChain(List<WebFilter> filters, WebHandler handler) {
DefaultWebFilterChain chain = new DefaultWebFilterChain(filters, handler, null, null);
ListIterator<? extends WebFilter> iterator = filters.listIterator(filters.size());
while (iterator.hasPrevious()) {
chain = new DefaultWebFilterChain(filters, handler, iterator.previous(), chain);
}
return chain;
}
public Mono<Void> filter(ServerWebExchange exchange) {
return Mono.defer(() ->
this.currentFilter != null && this.chain != null ?
invokeFilter(this.currentFilter, this.chain, exchange) :
this.handler.handle(exchange));
}
private Mono<Void> invokeFilter(WebFilter current, DefaultWebFilterChain chain, ServerWebExchange exchange) {
String currentName = current.getClass().getName();
return current.filter(exchange, chain).checkpoint(currentName + " [DefaultWebFilterChain]");
}
}DispatcherHandler Execution
public class DispatcherHandler implements WebHandler {
public Mono<Void> handle(ServerWebExchange exchange) {
if (this.handlerMappings == null) {
return createNotFoundError();
}
if (CorsUtils.isPreFlightRequest(exchange.getRequest())) {
return handlePreFlight(exchange);
}
return Flux.fromIterable(this.handlerMappings)
.concatMap(mapping -> mapping.getHandler(exchange))
.next()
.switchIfEmpty(createNotFoundError())
.flatMap(handler -> invokeHandler(exchange, handler))
.flatMap(result -> handleResult(exchange, result));
}
}The overall flow mirrors Spring MVC: handler mappings are located, a suitable handler adapter is chosen, the handler result is produced, and a result handler processes the response. The filter chain is built as a linked list where each WebFilter delegates to the next, ending with the DispatcherHandler.
Webfilter chain example: three filters are linked so that filter 3 calls filter 2, which calls filter 1, and finally the DispatcherHandler processes the request.
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.
