Deep Dive into Spring Cloud Gateway: Core Components and Source Code Walkthrough
This article provides a comprehensive walkthrough of Spring Cloud Gateway, covering its core concepts, architecture, key components such as Route, Predicate, and Filter, and detailed source‑code analysis with configuration examples and the underlying HTTP handling flow.
1. Introduction
Spring Cloud Gateway is part of the Spring Cloud ecosystem, built on Spring Boot 2.x, Spring WebFlux, and Project Reactor, using Netty as the underlying communication framework. It offers routing, rate limiting, circuit breaking, and other gateway core functions with high extensibility.
Note: It cannot run in a traditional Servlet container nor be packaged as a WAR.
Gateway Core Components
Route: The basic building block of the gateway, defined by an ID, destination URI, a set of predicates, and a set of filters. The route matches when all predicates evaluate to true.
Predicate: A Java 8 function predicate that receives a ServerWebExchange and can match any request attribute such as headers or parameters.
Filter: Instances of GatewayFilter built by specific factories, allowing modification of the request and response before or after downstream calls.
2. Source Code Analysis
Assume the following route configuration and analyze the processing flow step by step.
<code>spring:</code><code> cloud:</code><code> gateway:</code><code> default-filters:</code><code> - StripPrefix=1</code><code> routes:</code><code> - id: demo-service-01</code><code> uri: http://localhost:8081</code><code> # predicates</code><code> predicates:</code><code> - name: Path</code><code> args:</code><code> a: /api-1/**</code><code> # route filters</code><code> filters:</code><code> - name: CircuitBreaker</code><code> args:</code><code> name: myCircuitBreaker</code><code> fallbackUri: forward:/fallback</code><code> - id: demo-service-02</code><code> uri: http://localhost:8082</code><code> predicates:</code><code> - name: Path</code><code> args:</code><code> a: /api-2/**</code>The configuration defines two routes, demo-service-01 and demo-service-02 . The first route includes a circuit‑breaker filter that redirects to /fallback on errors, and both routes share the default StripPrefix=1 filter.
2.1 Underlying Service
The gateway runs on a reactor‑netty HttpServer wrapped as a WebServer . Incoming requests are handed to an HttpHandler for processing.
2.2 HttpHandler Initialization
<code>@Bean</code><code>public HttpHandler httpHandler(ObjectProvider<WebFluxProperties> propsProvider) {</code><code> HttpHandler httpHandler = WebHttpHandlerBuilder.applicationContext(this.applicationContext).build();</code><code>}</code>The WebHttpHandlerBuilder creates a DispatcherHandler , collects all WebFilter beans, and gathers WebExceptionHandler beans.
2.3 Core HttpHandler Logic
<code>public class HttpWebHandlerAdapter extends WebHandlerDecorator implements HttpHandler {</code><code> public Mono<Void> handle(ServerHttpRequest request, ServerHttpResponse response) {</code><code> return getDelegate().handle(exchange);</code><code> }</code><code>}</code>The delegate is an ExceptionHandlingWebHandler , which wraps a FilteringWebHandler .
2.4 DispatcherHandler
<code>public class DispatcherHandler implements WebHandler {</code><code> public Mono<Void> handle(ServerWebExchange exchange) {</code><code> return Flux.fromIterable(this.handlerMappings)</code><code> .concatMap(mapping -> mapping.getHandler(exchange))</code><code> .next()</code><code> .switchIfEmpty(createNotFoundError())</code><code> .flatMap(handler -> invokeHandler(exchange, handler))</code><code> .flatMap(result -> handleResult(exchange, result));</code><code> }</code><code>}</code>It works similarly to Spring MVC’s DispatcherServlet , locating the appropriate HandlerMapping and invoking the handler.
Routing Process
Locate the HandlerMapping for the current request (the RoutePredicateHandlerMapping ).
Obtain the corresponding HandlerAdapter ( SimpleHandlerAdapter ) which delegates to the FilteringWebHandler .
RoutePredicateHandlerMapping
<code>public class RoutePredicateHandlerMapping extends AbstractHandlerMapping {</code><code> protected Mono<?> getHandlerInternal(ServerWebExchange exchange) {</code><code> return lookupRoute(exchange)</code><code> .flatMap(route -> {</code><code> exchange.getAttributes().put(GATEWAY_ROUTE_ATTR, route);</code><code> return Mono.just(webHandler);</code><code> })</code><code> .switchIfEmpty(Mono.empty().then(Mono.fromRunnable(() -> {</code><code> exchange.getAttributes().remove(GATEWAY_PREDICATE_ROUTE_ATTR);</code><code> })));</code><code> }</code><code> protected Mono<Route> lookupRoute(ServerWebExchange exchange) {</code><code> return this.routeLocator.getRoutes()</code><code> .concatMap(route -> Mono.just(route).filterWhen(r -> {</code><code> exchange.getAttributes().put(GATEWAY_PREDICATE_ROUTE_ATTR, r.getId());</code><code> return r.getPredicate().apply(exchange);</code><code> }))</code><code> .next()</code><code> .map(route -> {</code><code> validateRoute(route, exchange);</code><code> return route;</code><code> });</code><code> }</code><code>}</code>The mapping stores the matched route in the exchange and returns the FilteringWebHandler for further processing.
Global Filters
#1 NettyWriteResponseFilter #2 RouteToRequestUrlFilter #3 ReactiveLoadBalancerClientFilter #4 NettyRoutingFilter #5 ForwardRoutingFilter
These filters handle the actual call to the downstream service.
NettyRoutingFilter (Request)
<code>public class NettyRoutingFilter implements GlobalFilter, Ordered {</code><code> public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {</code><code> URI requestUrl = exchange.getRequiredAttribute(GATEWAY_REQUEST_URL_ATTR);</code><code> Route route = exchange.getAttribute(GATEWAY_ROUTE_ATTR);</code><code> Flux<HttpClientResponse> responseFlux = getHttpClient(route, exchange)</code><code> .request(method).uri(url).send((req, nettyOutbound) -> {</code><code> return nettyOutbound.send(request.getBody().map(this::getByteBuf));</code><code> }).responseConnection((res, connection) -> Mono.just(res));</code><code> return responseFlux.then(chain.filter(exchange));</code><code> }</code><code>}</code>NettyWriteResponseFilter (Response)
<code>public class NettyWriteResponseFilter implements GlobalFilter, Ordered {</code><code> public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {</code><code> return chain.filter(exchange).then(Mono.defer(() -> {</code><code> Connection connection = exchange.getAttribute(CLIENT_RESPONSE_CONN_ATTR);</code><code> ServerHttpResponse response = exchange.getResponse();</code><code> Flux<DataBuffer> body = connection.inbound().receive().retain()</code><code> .map(byteBuf -> wrap(byteBuf, response));</code><code> MediaType contentType = null;</code><code> try { contentType = response.getHeaders().getContentType(); } catch (Exception ignored) {}</code><code> return (isStreamingMediaType(contentType)</code><code> ? response.writeAndFlushWith(body.map(Flux::just))</code><code> : response.writeWith(body));</code><code> }));</code><code> }</code><code>}</code>Diagram
The article concludes with a reminder that the content is for educational purposes and encourages readers to like, share, and collect the material.
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.