Spring Cloud Gateway Guide: Discovery, Hystrix, Custom Filters & Rate Limiting
This article demonstrates how to configure Spring Cloud Gateway with service discovery, two routing methods, integrate Hystrix for circuit breaking, implement global and custom token filters, and apply Redis‑based rate limiting, providing complete code snippets and configuration examples for a robust backend microservice architecture.
Environment: Spring Boot 2.3.10.RELEASE, Spring Cloud Hoxton.SR11, Spring Cloud Alibaba 2.2.5.RELEASE, Redis.
Dependencies
<dependencies>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
</dependencies>Service‑consumer module
@RestController
@RequestMapping("/consumer")
public class ConsumerController {
@Resource
private RestTemplate restTemplate;
@Resource
private HttpServletRequest request;
@GetMapping("/get")
public Object invoke(String serviceName) {
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
return restTemplate.getForObject(
"http://service-producer/discovery/get?serviceName=" + serviceName,
Object.class);
}
}Service‑producer module
@RestController
@RequestMapping("discovery")
public class DiscoveryController {
@NacosInjected
private NamingService namingService;
@Resource
private DiscoveryClient discoverClient;
@GetMapping(value = "/get")
public Object get(@RequestParam String serviceName) throws Exception {
Map<String, Object> res = new HashMap<>();
res.put("services", discoverClient.getServices());
res.put("instances", discoverClient.getInstances(serviceName));
res.put("port", 9000);
return res;
}
}Service discovery configuration
Method 1 (not recommended): enable gateway discovery locator to call services directly by name.
spring:
cloud:
gateway:
discovery:
locator:
enabled: true
lower-case-service-id: trueMethod 2: define explicit routes.
spring:
cloud:
gateway:
routes:
- id: gw001
uri: lb://service-consumer
predicates:
- Path=/api/**, /api-a/**, /api-b/**
filters:
- StripPrefix=1Hystrix integration
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency> spring:
cloud:
gateway:
routes:
- id: gw001
uri: lb://service-consumer
predicates:
- Path=/api/**, /api-a/**, /api-b/**
filters:
- StripPrefix=1
- name: Hystrix
args:
name: gatewayfallback
fallbackUri: forward:/gateway/error @RestController
@RequestMapping("/gateway")
public class DefaultController {
@RequestMapping("/error")
public Object error() {
Map<String, Object> result = new HashMap<>();
result.put("code", -1);
result.put("message", "服务不可用,请稍候再试");
result.put("data", null);
return result;
}
}Custom filters
Global filter that logs execution time:
@Component
public class GlobalExecutionTimeFilter implements GlobalFilter {
private static Logger logger = LoggerFactory.getLogger(GlobalExecutionTimeFilter.class);
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
long start = System.currentTimeMillis();
Mono<Void> result = chain.filter(exchange);
logger.info("本次任务执行时间:{}毫秒", (System.currentTimeMillis() - start));
return result;
}
}Token validation filter for specific routes:
@Component
public class TokenGatewayFilterFactory extends AbstractGatewayFilterFactory<TokenGatewayFilterFactory.TokenConfig> {
public static final String ENABLE_KEY = "enable";
public static final String EXCLUDE_KEY = "exclude";
public TokenGatewayFilterFactory() {
super(TokenConfig.class);
}
@Override
public List<String> shortcutFieldOrder() {
return Arrays.asList(ENABLE_KEY, EXCLUDE_KEY);
}
@Override
public GatewayFilter apply(TokenConfig config) {
return (exchange, chain) -> {
if (!config.isEnable()) {
return chain.filter(exchange);
}
ServerHttpRequest request = exchange.getRequest();
ServerHttpResponse response = exchange.getResponse();
String token = request.getHeaders().getFirst("access-token");
if (token == null || "".equals(token)) {
token = request.getQueryParams().getFirst("access-token");
}
if (token == null || "".equals(token)) {
DataBuffer data = setErrorInfo(response, "请检查Token是否填写");
return response.writeWith(Mono.just(data));
}
return chain.filter(exchange);
};
}
private DataBuffer setErrorInfo(ServerHttpResponse response, String msg) {
HttpHeaders httpHeaders = response.getHeaders();
httpHeaders.add("Content-Type", "application/json; charset=UTF-8");
httpHeaders.add("Cache-Control", "no-store, no-cache, must-revalidate, max-age=0");
String body = "{\"code\":-1, \"message\": \"" + msg + "\"}";
return response.bufferFactory().wrap(body.getBytes());
}
public static class TokenConfig {
private boolean enable;
private String exclude;
public boolean isEnable() { return enable; }
public void setEnable(boolean enable) { this.enable = enable; }
public String getExclude() { return exclude; }
public void setExclude(String exclude) { this.exclude = exclude; }
}
}Rate limiting
Add Redis and commons‑pool2 dependencies, then configure the RequestRateLimiter filter.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency> spring:
cloud:
gateway:
routes:
- id: gw001
uri: lb://service-consumer
predicates:
- Path=/api/**, /api-a/**, /api-b/**
filters:
- StripPrefix=1
- name: RequestRateLimiter
args:
keyResolver: '#{@redisKeyResolver}'
redis-rate-limiter.replenishRate: 1
redis-rate-limiter.burstCapacity: 2 @Component
public class RedisKeyResolver implements KeyResolver {
// Rate limiting based on client IP
@Override
public Mono<String> resolve(ServerWebExchange exchange) {
String address = exchange.getRequest().getRemoteAddress().getHostString();
return Mono.just(address);
}
}When requests exceed the configured rate, the gateway returns HTTP 429.
All steps above complete a full Spring Cloud Gateway setup with discovery, circuit breaking, custom filtering, and rate limiting.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
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.
