Spring Cloud Gateway
Introduction
Spring Cloud Gateway is a powerful, modern API gateway built on Spring Framework 5, Spring Boot 2, and Project Reactor. It's designed to provide a simple yet effective way to route requests to your microservices, apply cross-cutting concerns, and secure your applications in a microservices architecture.
In a microservices environment, an API gateway serves as the single entry point for clients, handling requests by routing them to appropriate services, applying transformations, and implementing cross-cutting concerns like authentication, monitoring, and rate limiting. Spring Cloud Gateway excels in this role with its non-blocking, reactive design.
Why Use Spring Cloud Gateway?
- Reactive Design: Built on Spring WebFlux, it offers non-blocking I/O for handling high concurrency with fewer resources
- Dynamic Routing: Route traffic to different services based on various predicates
- Circuit Breaking: Integration with resilience tools like Resilience4j
- Filtering Capabilities: Pre and post-filtering for cross-cutting concerns
- Spring Ecosystem Integration: Seamless integration with Spring Cloud Discovery, Config, and Security
Getting Started
Setting Up Your Project
Let's start by creating a basic Spring Cloud Gateway application:
- Create a new Spring Boot project with Spring Cloud Gateway dependency.
You can use Spring Initializer (https://start.spring.io/) with the following dependencies:
- Spring Cloud Gateway
- Spring Boot DevTools (optional)
Alternatively, add the following to your pom.xml
:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
Make sure you have the Spring Cloud dependencies management:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<properties>
<spring-cloud.version>2023.0.0</spring-cloud.version>
</properties>
Basic Configuration
Create a simple application that routes requests to example.org:
@SpringBootApplication
public class GatewayApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class, args);
}
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
return builder.routes()
.route("example_route", r -> r
.path("/example/**")
.uri("https://example.org"))
.build();
}
}
This configuration creates a route that forwards any request coming to /example/**
to https://example.org
.
Alternatively, you can configure routes in the application.yml
file:
spring:
cloud:
gateway:
routes:
- id: example_route
uri: https://example.org
predicates:
- Path=/example/**
Core Concepts
Route
A route is the primary API element in Spring Cloud Gateway. It consists of:
- ID: Unique identifier for the route
- Destination URI: Where the request should be sent
- Predicates: Conditions that must be met for the route to be matched
- Filters: Operations to modify the request or response
Predicates
Predicates determine if a route matches a given request. Spring Cloud Gateway includes many built-in predicates:
Predicate | Description | Example |
---|---|---|
Path | Matches on request path | Path=/orders/** |
Method | Matches HTTP method | Method=GET,POST |
Header | Matches header value | Header=X-Request-Id, \d+ |
Host | Matches host header | Host=**.example.org |
Cookie | Matches cookie value | Cookie=sessionId, \d+ |
Query | Matches query parameter | Query=id, \d+ |
After/Before/Between | Time-based matching | After=2023-01-01T00:00:00+01:00[Europe/Paris] |
Example with multiple predicates:
spring:
cloud:
gateway:
routes:
- id: user_service_route
uri: lb://user-service
predicates:
- Path=/users/**
- Method=GET,POST
- Header=X-Api-Version, v1
This route will only match requests that:
- Have a path starting with
/users/
- Use either GET or POST method
- Include header
X-Api-Version: v1
Filters
Filters modify the incoming request or outgoing response. They can be global (applied to all routes) or specific to a route.
Here are some common built-in gateway filters:
Request Modification Filters
spring:
cloud:
gateway:
routes:
- id: add_request_header_route
uri: https://example.org
predicates:
- Path=/headers
filters:
- AddRequestHeader=X-Request-Foo, Bar
- PrefixPath=/api
- StripPrefix=1
This configuration:
- Adds a header
X-Request-Foo: Bar
to the request - Adds prefix
/api
to the path - Removes the first path segment
Response Modification Filters
filters:
- AddResponseHeader=X-Response-Foo, Bar
- RemoveResponseHeader=Sensitive-Header
- SetStatus=201
Implementing Custom Filters
You can create custom filters by implementing either GatewayFilter
or GlobalFilter
:
@Component
public class CustomGlobalFilter implements GlobalFilter {
private static final Logger log = LoggerFactory.getLogger(CustomGlobalFilter.class);
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
log.info("Processing request: {}", exchange.getRequest().getPath());
// Add custom header
ServerHttpRequest request = exchange.getRequest().mutate()
.header("X-Custom-Header", "custom-value")
.build();
return chain.filter(exchange.mutate().request(request).build())
.then(Mono.fromRunnable(() -> {
log.info("Response status: {}", exchange.getResponse().getStatusCode());
}));
}
}
Practical Examples
Load Balancing with Service Discovery
Spring Cloud Gateway integrates seamlessly with service discovery tools like Eureka:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
spring:
application:
name: api-gateway
cloud:
gateway:
discovery:
locator:
enabled: true # Enable service discovery
lower-case-service-id: true
routes:
- id: user-service
uri: lb://USER-SERVICE # 'lb://' prefix for load balancing
predicates:
- Path=/users/**
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
With this configuration, requests to /users/**
will be load-balanced across all instances of USER-SERVICE
registered in Eureka.
Rate Limiting
You can implement rate limiting using the RequestRateLimiter
filter with Redis:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>
spring:
cloud:
gateway:
routes:
- id: rate-limited-route
uri: https://example.org
predicates:
- Path=/api/**
filters:
- name: RequestRateLimiter
args:
redis-rate-limiter.replenishRate: 10
redis-rate-limiter.burstCapacity: 20
key-resolver: "#{@userKeyResolver}"
Define the key resolver in your configuration:
@Bean
public KeyResolver userKeyResolver() {
return exchange -> Mono.just(exchange.getRequest()
.getRemoteAddress()
.getHostString());
}
This limits requests based on the client's IP address, allowing 10 requests per second with a burst capacity of 20.
Circuit Breaking with Resilience4j
Add circuit breaking to protect your services from cascading failures:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-circuitbreaker-reactor-resilience4j</artifactId>
</dependency>
spring:
cloud:
gateway:
routes:
- id: circuit-breaker-route
uri: lb://order-service
predicates:
- Path=/orders/**
filters:
- name: CircuitBreaker
args:
name: orderCircuitBreaker
fallbackUri: forward:/fallback/orders
Implement a fallback controller:
@RestController
@RequestMapping("/fallback")
public class FallbackController {
@GetMapping("/orders")
public Mono<Map<String, String>> orderFallback() {
Map<String, String> response = new HashMap<>();
response.put("message", "Order service is currently unavailable. Please try again later.");
response.put("timestamp", LocalDateTime.now().toString());
return Mono.just(response);
}
}
Authentication and Authorization
Integrate with Spring Security OAuth2:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
@Configuration
public class SecurityConfig {
@Bean
public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
http
.authorizeExchange()
.pathMatchers("/public/**").permitAll()
.pathMatchers("/api/admin/**").hasRole("ADMIN")
.anyExchange().authenticated()
.and()
.oauth2Login()
.and()
.oauth2ResourceServer()
.jwt();
return http.build();
}
}
Performance Considerations
-
Use Non-blocking APIs: Spring Cloud Gateway is built on reactive principles, so use non-blocking calls whenever possible.
-
Tune Thread Pool Size: If integrating with blocking APIs, configure the thread pool size appropriately:
spring:
cloud:
gateway:
httpclient:
pool:
max-connections: 200
acquire-timeout: 5000
max-idle-time: 15000
- Enable Response Caching: Implement caching for appropriate endpoints:
spring:
cloud:
gateway:
routes:
- id: cacheable_route
uri: https://example.org
predicates:
- Path=/cacheable/**
filters:
- name: Retry
args:
retries: 3
statuses: BAD_GATEWAY
- name: CachingRequestBodyGatewayFilter
args:
max-size: 10000
Monitoring and Observability
Spring Cloud Gateway provides metrics out of the box with Spring Boot Actuator:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
management:
endpoints:
web:
exposure:
include: gateway,health,info,metrics
endpoint:
gateway:
enabled: true
health:
show-details: always
This exposes:
/actuator/gateway/routes
: Lists all configured routes/actuator/gateway/routes/{id}
: Information about a specific route/actuator/gateway/globalfilters
: Lists all global filters/actuator/gateway/routefilters
: Lists all route filters
Summary
Spring Cloud Gateway provides a modern, reactive API gateway solution for microservices architectures with:
- Dynamic routing based on various predicates
- Powerful filtering capabilities for cross-cutting concerns
- Seamless integration with Spring Cloud ecosystem
- High performance through its non-blocking design
- Extensive monitoring capabilities
With its declarative configuration and flexibility, Spring Cloud Gateway enables developers to focus on business logic while providing robust edge functionality like security, resilience, and observability.
Additional Resources
- Spring Cloud Gateway Official Documentation
- Spring Cloud Gateway GitHub Repository
- Building Microservices with Spring Cloud Gateway
Exercises
- Create a gateway that routes requests to two different backend services based on path.
- Implement rate limiting for a specific endpoint to allow only 5 requests per minute per client.
- Add a circuit breaker with a custom fallback response for a service route.
- Implement a custom filter that adds correlation IDs to all incoming requests.
- Configure the gateway to integrate with a service discovery system like Eureka.
If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)