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.

Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
How Spring WebFlux Handles HTTP Requests: From HttpHandler to DispatcherHandler

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.
Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

WebFlux
Spring Full-Stack Practical Cases
Written by

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.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.