skip to content

Global Filters & Chain

GlobalFilters apply to every route in a defined order, and the routing filters at the end of the chain make the actual proxied call. Interviewers ask where you would put authentication or correlation-id propagation, and this is the answer.

part ofSpring Frameworkoverview, primer and where to startread it →
on this pageshow

questions

5

What is a GlobalFilter in Spring Cloud Gateway, and how does it differ from a GatewayFilter?

level: juniorimportance: must knowfreq 70%

answer

  1. GlobalFilter = all routes, GatewayFilter = one route
  2. Same filter(exchange, chain) signature
  3. GatewayFilterAdapter wraps global into the combined chain
  4. Cross-cutting (auth/log/route) vs per-route transforms
  5. One sorted chain, not two

basics

~20 s

A GlobalFilter runs on every route automatically. A GatewayFilter is configured per route. Both intercept the request/response; the difference is scope — global applies to all routes, gateway filters only to routes you attach them to.

solid answer

~40 s

GlobalFilter is an interface (`Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain)`) whose beans are applied to every matched route with no per-route configuration. GatewayFilter is the same shape but scoped to a single route, wired via `filters:` in config or the Java DSL (e.g. AddRequestHeader). Internally Gateway wraps each GlobalFilter in a GatewayFilterAdapter and merges it with that route's own GatewayFilters into one combined, sorted chain. So both coexist in the same chain — global ones are simply present on all routes. You reach for a GlobalFilter for cross-cutting concerns (auth, logging, metrics, tracing, the proxied call), and a GatewayFilter for behavior only some routes need.

code

java · 14 lines
java
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;

@Component // a bean => applied to EVERY route
public class LoggingGlobalFilter implements GlobalFilter {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        System.out.println("--> " + exchange.getRequest().getURI());
        return chain.filter(exchange); // delegate to the rest of the chain
    }
}

go deeper

for a junior

Know global = every route, gateway = per route, and both intercept request/response.

for a middle

Explain they're merged into one sorted chain via GatewayFilterAdapter.

for a senior

Discuss the exchange attributes handoff and cost of global filters on all traffic.

for a principal

Reason about where to place cross-cutting concerns and how to scope-guard a global filter without per-route config.

**Spring Cloud Gateway** is a reactive API gateway built on Spring WebFlux and Project Reactor. A request that matches a **Route** flows through a chain of filters before the gateway proxies it downstream and writes the response back. **GlobalFilter** is the interface: ```java public interface GlobalFilter { Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain); } ``` Any Spring bean implementing `GlobalFilter` is applied to **every** route the gateway serves — you never list it per route. This is where cross-cutting concerns live: authentication, request logging, correlation IDs, metrics, and the built-in routing filters (`NettyRoutingFilter`, `ForwardRoutingFilter`, `ReactiveLoadBalancerClientFilter`) that actually perform or prepare the proxied call. **GatewayFilter** is a similar interface but is attached to an individual route. You configure it declaratively: ```yaml spring: cloud: gateway: routes: - id: users uri: http://users-svc:8080 predicates: [Path=/users/**] filters: - AddRequestHeader=X-Tenant, acme ``` Here `AddRequestHeader` only affects the `users` route. **How they run together:** the `FilteringWebHandler` takes the route's GatewayFilters, then wraps every `GlobalFilter` bean in a `GatewayFilterAdapter` (an adapter that makes a GlobalFilter look like a GatewayFilter). It combines both lists and sorts the whole thing by `Ordered`/`@Order` using `AnnotationAwareOrderComparator`. The result is a single `DefaultGatewayFilterChain`. Thus at runtime there is no separate "global chain" vs "route chain" — it is one ordered list, and a global filter can be positioned before or after route filters purely by its order value. **ServerWebExchange** is the reactive request/response context passed to every filter; it carries the request, response, and a mutable attributes map (`exchange.getAttributes()`) that filters use to hand data to one another (e.g. the resolved downstream URL). **When to use which:** GlobalFilter for anything that must apply everywhere (security, observability, the routing mechanics). GatewayFilter for per-route transformations (header rewriting, path stripping, rate limiting on specific routes). **Gotcha:** because a GlobalFilter runs on *every* route, an expensive or blocking operation inside one hurts all traffic. Keep them non-blocking and cheap, and guard by predicate/attribute if you only care about some requests.

  • How would you make a GlobalFilter effectively apply to only some routes?
    A GlobalFilter always runs on every route, so you guard inside it — check a request attribute, path, or a route-level attribute (e.g. via the route's metadata) and short-circuit with `chain.filter(exchange)` unchanged when it does not apply. If you truly need per-route scoping, use a GatewayFilter/GatewayFilterFactory instead.
  • Do you have to annotate a GlobalFilter with @Component?
    You need it to be a Spring bean — @Component works, or a @Bean method in a @Configuration class. Any GlobalFilter bean is auto-discovered and added to the chain for all routes.

saying these in an interview costs you the question

  • Claiming a GlobalFilter can be listed under a specific route's `filters:`
  • Thinking global and route filters run in two separate chains
  • Saying GlobalFilter and GatewayFilter have different method signatures

context

open as a page

How is the order of filters determined in Spring Cloud Gateway, and how does implementing Ordered affect a GlobalFilter?

level: middleimportance: must knowfreq 65%

basics

~20 s

Filters are sorted by their order value (lower runs first on the way in). A GlobalFilter can implement Ordered or use @Order to control its position. The built-in routing filters use the lowest precedence so they run last.

open as a page

Explain GatewayFilterChain delegation: how does chain.filter(exchange) work and how do you add pre- and post-processing in a GlobalFilter?

level: seniorimportance: must knowfreq 60%

basics

~20 s

Each filter does its pre-work, then calls chain.filter(exchange) to pass control to the next filter, returning a Mono. To do post-work, chain .then(...) or .doFinally(...) onto that Mono so it runs after downstream filters complete.

open as a page

What do NettyRoutingFilter and ForwardRoutingFilter do, and how does the gateway decide which one performs the proxied call?

level: seniorimportance: should knowfreq 45%

basics

~20 s

They are the terminal GlobalFilters that actually make the call. NettyRoutingFilter proxies http/https URIs using a Netty HTTP client. ForwardRoutingFilter handles forward: URIs by dispatching locally in the same gateway app. The URI scheme decides which runs.

open as a page

You need cross-cutting timing metrics plus a filter that runs immediately before the downstream call. How do you design the ordering, and what constraints do the terminal routing filters impose?

level: principalimportance: should knowfreq 30%

basics

~20 s

Put the timing filter at a very low order so it wraps everything, doing pre-work first and post-work last via .then(). Any "just before the call" work must also go pre-side at a high order (near, but before, LOWEST_PRECEDENCE), because the routing filter is terminal and won't run anything after it on the pre path.

open as a page