What is a Spring WebFlux `WebFilter`, and how does it relate to the servlet `Filter`?
answer
- reactive twin of servlet Filter
- filter(exchange, chain) -> Mono<Void>
- return chain.filter(exchange) to continue
- register = just be a bean
- ServerWebExchange, not HttpServletRequest
basics
~10 sWebFilter is WebFlux's reactive interface for intercepting every request/response, the non-blocking equivalent of a servlet Filter. Its filter(exchange, chain) method returns Mono<Void>, and you call chain.filter(exchange) to continue to the next filter or handler.
solid answer
~40 s`org.springframework.web.server.WebFilter` is the reactive analogue of the servlet `Filter`. In a WebFlux (Reactor Netty / non-blocking) app there is no `HttpServletRequest`; instead a filter receives a `ServerWebExchange` (wrapping the reactive request and response) and a `WebFilterChain`. Its single method `Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain)` returns a `Mono<Void>` that completes when processing is done. To pass control down the chain you return `chain.filter(exchange)`. Register a filter simply by declaring it as a Spring bean; the framework discovers all `WebFilter` beans, orders them, and wraps every request — annotated controllers and functional endpoints alike. Typical uses: logging, adding/reading headers, tracing, correlation IDs, auth pre-checks. Crucially the work is non-blocking: you compose on the returned `Mono` rather than executing imperatively then returning.
code
java · 18 linesimport org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono;
@Component
public class RequestLoggingFilter implements WebFilter {
@Override
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
String method = exchange.getRequest().getMethod().name();
String path = exchange.getRequest().getPath().value();
// Continue the chain; log after it completes (non-blocking).
return chain.filter(exchange)
.doFinally(signal -> System.out.println(method + " " + path + " -> " + signal));
}
}go deeper
Know it's the reactive Filter, the signature returns Mono<Void>, and you call chain.filter(exchange) to continue.
Explain registration by bean, that it wraps every request, and the non-blocking 'return the Mono' idiom vs servlet's void return.
Contrast with servlet Filter table, explain where it sits in the HttpHandler/WebHandler pipeline, and the no-blocking rule.
Frame Spring Security reactive as a WebFilter chain; discuss why the reactive analogue needs a Mono<Void> return for backpressure/completion semantics.
## What it is `WebFilter` (full name `org.springframework.web.server.WebFilter`) is the interceptor abstraction of the **Spring WebFlux** reactive web stack. WebFlux is Spring's non-blocking web framework built on **Project Reactor** (`Mono`/`Flux`) and typically running on **Reactor Netty**, an event-loop server that handles many concurrent connections on a small thread pool without one-thread-per-request. Because there is no Servlet API in the pure-reactive stack, there is no `javax.servlet.Filter`, no `HttpServletRequest`, and no `FilterChain`. `WebFilter` fills that role. ## The interface ```java public interface WebFilter { Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain); } ``` - **`ServerWebExchange`** is the reactive container for one HTTP exchange. It exposes `getRequest()` (a `ServerHttpRequest`), `getResponse()` (a `ServerHttpResponse`), request attributes (`getAttributes()`), the `getSession()` (a `Mono<WebSession>`), and `getPrincipal()`. - **`WebFilterChain`** is the reactive analogue of the servlet `FilterChain`. Calling `chain.filter(exchange)` invokes the next filter, and eventually the `WebHandler` (which dispatches to your controller / functional endpoint). It returns a `Mono<Void>`. - The method returns **`Mono<Void>`** — a reactive stream that emits no value and simply signals *completion* (or error) when the whole downstream pipeline finishes. ## How you continue the chain Unlike a servlet filter where you call `chain.doFilter(req, res)` imperatively and then return, here you **return the Mono** produced by the chain: ```java return chain.filter(exchange); ``` Anything you compose onto that Mono (`.then(...)`, `.doFinally(...)`, `.contextWrite(...)`) runs as part of the reactive pipeline. ## Registration and discovery You do **not** register a `WebFilter` in `web.xml` or with `FilterRegistrationBean` (that is the servlet world). You just declare it as a Spring bean (`@Component`, or an `@Bean` method). At startup `WebHttpHandlerBuilder` collects all `WebFilter` beans, sorts them, and composes them into the reactive handler chain. They apply to **every** request handled by WebFlux — both `@RestController`/`@Controller` endpoints and `RouterFunction` (functional) endpoints. ## Where it sits The reactive pipeline is roughly: `HttpHandler` → `WebHandler` (the `WebFilter` chain lives here) → `DispatcherHandler` → `HandlerMapping`/`HandlerAdapter` → your controller. So `WebFilter`s wrap the whole handler dispatch. ## Relationship to the servlet Filter (side-by-side) | Servlet MVC | WebFlux | |---|---| | `javax.servlet.Filter` | `WebFilter` | | `doFilter(req, res, chain)` returns `void` | `filter(exchange, chain)` returns `Mono<Void>` | | `HttpServletRequest`/`Response` | `ServerHttpRequest`/`Response` via `ServerWebExchange` | | `FilterChain.doFilter(...)` | `chain.filter(exchange)` | | Blocking imperative code | Non-blocking reactive composition | (Servlet filters themselves are out of scope here — they belong to the MVC stack.) ## Common gotchas - **Never block.** Don't do JDBC/`RestTemplate`/`Thread.sleep` in a filter running on the event loop; it starves the server. - **You must return a Mono.** Forgetting to return `chain.filter(exchange)` (or returning `Mono.empty()` by accident) silently drops the request — the handler never runs. - **`ServerWebExchange` is effectively immutable**; to change the request/response you call `exchange.mutate()` and pass the new exchange down (covered in a later question). ## When to use Cross-cutting concerns that must see every request: logging/tracing, correlation IDs, request/response header manipulation, metrics, coarse auth pre-checks. Spring Security's reactive stack is itself implemented as a chain of `WebFilter`s.
- How do you register a WebFilter — do you need FilterRegistrationBean?No. `FilterRegistrationBean` is for servlet filters. For a `WebFilter` you just expose it as a Spring bean (`@Component` or `@Bean`); `WebHttpHandlerBuilder` discovers and wires all `WebFilter` beans automatically.
- What happens if your filter never calls chain.filter(exchange)?You short-circuit the request — the downstream filters and the handler never run. That's how you deliberately reject a request (return `exchange.getResponse().setComplete()` after setting a status), but doing it accidentally drops the request.
saying these in an interview costs you the question
- Thinking WebFilter is the same class as the servlet Filter (or that you register it with FilterRegistrationBean)
- Doing blocking I/O inside a WebFilter on the event loop
- Not returning the Mono from chain.filter(exchange), assuming imperative return like doFilter