skip to content

Gateway Server MVC (Servlet)

The servlet variant of the gateway builds routes from RouterFunctions and proxies with RestClient, giving you the same model on a blocking stack. A good answer when the team knows MVC and does not want to learn Reactor for the edge.

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

questions

5

What is Spring Cloud Gateway Server MVC, and how does it differ from the reactive Gateway?

level: juniorimportance: must knowfreq 55%

answer

  1. Servlet stack, thread-per-request
  2. RouterFunctions + predicates + HandlerFilterFunctions
  3. http() proxies via blocking RestClient
  4. Sibling of reactive Netty gateway
  5. Pairs well with virtual threads

basics

~10 s

It is the API gateway built on blocking Spring MVC (servlet stack) instead of reactive WebFlux/Netty. It runs on a servlet container with thread-per-request and proxies calls using a blocking RestClient.

solid answer

~40 s

Spring Cloud Gateway Server MVC is the servlet-based flavor of Spring Cloud Gateway. Instead of running on WebFlux/Netty with a reactive, event-loop model, it runs on the Spring MVC servlet stack (Tomcat/Jetty) with the classic thread-per-request model. You define routes with the functional web MVC DSL (RouterFunctions), predicates decide which requests match, HandlerFilterFunctions transform request/response, and the terminal handler proxies upstream using a blocking RestClient. You choose it when your app and libraries are blocking, when you want to reuse the servlet/MVC ecosystem (servlet filters, Spring MVC debugging, blocking security), or you don't want to adopt reactive programming. Functionally it offers the same gateway concept (routing, predicates, filters) but with a synchronous programming model; the reactive gateway is a separate sibling module for non-blocking, high-concurrency workloads.

code

java · 18 lines
java
import org.springframework.cloud.gateway.server.mvc.handler.GatewayRouterFunctions;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.function.RouterFunction;
import org.springframework.web.servlet.function.ServerResponse;

import static org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions.http;
import static org.springframework.cloud.gateway.server.mvc.predicate.GatewayRequestPredicates.path;

@Configuration
class GatewayRoutes {
    @Bean
    RouterFunction<ServerResponse> ordersRoute() {
        return GatewayRouterFunctions.route("orders")
                .route(path("/orders/**"), http("https://orders-service:8080"))
                .build();
    }
}

go deeper

for a junior

Know it's the blocking/servlet version of the gateway, contrasted with reactive Netty.

for a middle

Should name RouterFunctions, predicates, filters, and the RestClient proxy.

for a senior

Explains threading tradeoffs and when to pick MVC vs reactive.

for a principal

Frames it as an architectural choice tied to blocking ecosystems and virtual threads; knows the modules are mutually exclusive.

**What it is.** Spring Cloud Gateway is an API gateway: a service that sits in front of your microservices and routes/filters/transforms incoming HTTP requests. Historically Gateway was built only on **Spring WebFlux** (reactive, non-blocking, runs on Netty with an event loop). **Gateway Server MVC** is a second implementation built on the **Spring MVC servlet stack** — it runs inside a servlet container (Tomcat by default, or Jetty/Undertow) using the traditional **thread-per-request** model where each in-flight request occupies a platform thread until it completes. **Why two variants.** The reactive gateway is excellent for very high concurrency because a few event-loop threads handle thousands of connections, but it forces the whole request path to be non-blocking (reactive types, no blocking calls). Many teams have blocking codebases, blocking security, blocking libraries, or simply don't want reactive programming's complexity. Gateway Server MVC gives them the same gateway feature set on a familiar synchronous model. **How it is wired.** You add the starter `spring-cloud-starter-gateway-server-webmvc` (older coordinates: `spring-cloud-starter-gateway-mvc`). It is **not** interchangeable with the reactive starter — mixing them in one app is unsupported; pick one. Routes are expressed either in configuration (`spring.cloud.gateway.mvc.routes` / newer `spring.cloud.gateway.server.webmvc.routes`) or, more idiomatically, as `RouterFunction<ServerResponse>` beans built with `GatewayRouterFunctions.route(id)`. **Core building blocks:** - **Predicates** — `org.springframework.cloud.gateway.server.mvc.predicate.GatewayRequestPredicates` (e.g. `path()`, `host()`, `method()`, `header()`). They are `RequestPredicate`s from Spring MVC's functional web (`org.springframework.web.servlet.function`). A request must match to select the route. - **Handler** — the terminal that actually forwards the request. `org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions.http(...)` returns a `HandlerFunction<ServerResponse>` that proxies to the upstream URI using a **blocking RestClient**. - **Filters** — `HandlerFilterFunction<ServerResponse, ServerResponse>` applied `.before(...)`/`.after(...)`/`.filter(...)`, from factory classes like `BeforeFilterFunctions`, `AfterFilterFunctions`, `CircuitBreakerFilterFunctions`, `LoadBalancerFilterFunctions`. **Key differences vs reactive gateway (memorize):** 1. Runtime: servlet container + thread-per-request vs Netty + event loop. 2. Programming model: blocking/synchronous vs reactive `Mono`/`Flux`. 3. Proxy client: blocking `RestClient` vs reactive `WebClient`. 4. Web layer: Spring MVC functional (`org.springframework.web.servlet.function`) vs WebFlux functional (`org.springframework.web.reactive.function`). 5. Ecosystem reuse: servlet filters, `HandlerInterceptor`, blocking Spring Security vs their reactive equivalents. **Gotchas.** Under load the thread-per-request model can exhaust the thread pool while threads block on slow upstreams; pairing it with **virtual threads** (`spring.threads.virtual.enabled=true` on Java 21+) largely removes that cost. Don't try to add reactive filters or `WebFilter`s — the MVC variant uses servlet-world types. **When to use.** Choose MVC when your stack is blocking, you want MVC/servlet familiarity, or you run virtual threads; choose reactive when you need maximum connection scalability with a non-blocking pipeline end to end.

  • Can you run the reactive and MVC gateways in the same application?
    No. They are separate starters with different (WebFlux vs servlet) web stacks; you pick one per application. Mixing them is unsupported and the wrong functional web types won't line up.
  • What runtime concern does the MVC gateway have that the reactive one avoids, and how do you mitigate it?
    Thread-per-request means blocked upstream calls tie up platform threads, risking pool exhaustion under high concurrency. Mitigate with a larger pool, timeouts/circuit breakers, or (best) virtual threads via spring.threads.virtual.enabled=true on Java 21+.

context

open as a page

How do you define a route programmatically in Gateway Server MVC using the RouterFunctions DSL?

level: middleimportance: must knowfreq 50%

basics

~10 s

Declare a RouterFunction<ServerResponse> bean built with GatewayRouterFunctions.route(id), pairing a predicate (like path("/api/**")) with the http() handler that names the upstream URI, then call build().

open as a page

How do HandlerFilterFunctions work in Gateway Server MVC, and how do before/after/filter differ?

level: seniorimportance: should knowfreq 42%

basics

~10 s

Filters are HandlerFilterFunctions that wrap the handler. before-filters transform the ServerRequest, after-filters transform the ServerResponse, and a full filter wraps both sides and can short-circuit. Add them from factories like BeforeFilterFunctions and AfterFilterFunctions.

open as a page

How does RestClient-based proxying work in Gateway Server MVC, and how is the proxy client configured?

level: seniorimportance: should knowfreq 35%

basics

~20 s

The terminal http() handler forwards the incoming request to the upstream URI using a blocking RestClient: it copies method, path, headers and body, calls the backend synchronously, and streams the response back as a ServerResponse.

open as a page

As an architect, when would you choose Gateway Server MVC over the reactive gateway, and what are the tradeoffs?

level: principalimportance: should knowfreq 30%

basics

~10 s

Choose MVC when your stack is blocking or your team wants the familiar servlet/MVC model — especially with virtual threads. Choose reactive for maximum non-blocking concurrency. The tradeoff is thread-per-request simplicity vs event-loop scalability.

open as a page