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.

Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Spring Cloud Gateway Guide: Discovery, Hystrix, Custom Filters & Rate Limiting

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: true

Method 2: define explicit routes.

spring:
  cloud:
    gateway:
      routes:
        - id: gw001
          uri: lb://service-consumer
          predicates:
            - Path=/api/**, /api-a/**, /api-b/**
          filters:
            - StripPrefix=1

Hystrix 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.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

service discoveryrate limitingSpring CloudHystrixCustom Filters
Spring Full-Stack Practical Cases
Written by

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.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.