Mastering API Rate Limiting in Spring Boot 3: Guava, Gateway, and Redis
This guide explains why API rate limiting is essential, outlines common algorithms, and walks through three practical implementations in Spring Boot 3—using Guava, Spring Cloud Gateway with RedisRateLimiter, and a custom annotation‑based solution with Redis backing.
Overview
API rate limiting restricts access to endpoints to protect a system from overload, DDoS attacks, or malicious traffic, while ensuring stability and reliability for legitimate users.
Common limiting techniques include:
Counter – track request count per endpoint and block when a threshold is exceeded.
Rate limit – limit requests per second (or other time unit).
Sliding window – count requests within a moving time window.
Token bucket – allow a fixed number of requests in a given period regardless of burstiness.
Flow‑based – limit traffic based on network flow, such as per‑IP bandwidth.
Proper configuration balances protection with user experience.
Implementation Options
1. Guava RateLimiter
<code>@Test
public void testWithRateLimiter() {
long start = System.currentTimeMillis();
// Allow up to 10 requests per second
RateLimiter limiter = RateLimiter.create(10.0);
for (int i = 0; i < 10; i++) {
// Blocks if no permit is available
limiter.acquire();
System.out.println("execution business invoke...");
TimeUnit.SECONDS.sleep(1);
}
long end = System.currentTimeMillis();
System.out.println((end - start) + "ms");
}
</code>2. Spring Cloud Gateway with RedisRateLimiter
Spring Cloud Gateway provides the RequestRateLimiterGatewayFilterFactory filter, which uses RedisRateLimiter by default. You can customize the RateLimiter implementation as needed.
<code>spring:
cloud:
gateway:
routes:
- id: test
uri: http://localhost:8082
filters:
- name: RequestRateLimiter
args:
key-resolver: '#{@packKeyResolver}'
redis-rate-limiter.replenishRate: 1
redis-rate-limiter.burstCapacity: 3
</code>3. Resilience4j
Resilience4j also offers rate‑limiting capabilities that can be applied programmatically or via annotations. Refer to the official Resilience4j documentation for details.
Custom Annotation‑Based Rate Limiting (Core Solution)
Annotation Definition
<code>@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface AccessLimit {
// Time window in seconds
long seconds() default 1;
// Maximum number of calls within the window
int count() default 10;
}
</code>Interceptor
<code>@Component
public class AccessLimitInterceptor implements HandlerInterceptor {
@Resource
private StringRedisTemplate stringRedisTemplate;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
if (handler instanceof HandlerMethod handlerMethod) {
Method method = handlerMethod.getMethod();
AccessLimit accessLimit = method.getDeclaredAnnotation(AccessLimit.class);
if (accessLimit != null) {
long seconds = accessLimit.seconds();
int count = accessLimit.count();
if (seconds > 0 && count >= 0) {
String key = request.getRemoteAddr() + ":" + request.getRequestURI();
String value = stringRedisTemplate.opsForValue().get(key);
System.out.println("Current value: " + value);
if (value == null) {
stringRedisTemplate.opsForValue().set(key, String.valueOf(count - 1), seconds, TimeUnit.SECONDS);
return true;
} else {
int c = Integer.valueOf(value);
if (c <= 0) {
response.setContentType("application/json;charset=utf-8");
Map<String, Object> res = Map.of(
"code", -1,
"message", "Too many requests"
);
response.getWriter().println(new ObjectMapper().writeValueAsString(res));
return false;
} else {
stringRedisTemplate.opsForValue().decrement(key);
return true;
}
}
}
}
}
return true;
}
}
</code>Interceptor Registration
<code>@Component
public class AccessLimitConfig implements WebMvcConfigurer {
@Resource
private AccessLimitInterceptor accessLimitInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(accessLimitInterceptor)
.addPathPatterns("/**")
.excludePathPatterns("/login", "/logout");
}
}
</code>Controller Example
<code>@RestController
@RequestMapping("/acc")
public class AccessLimitController {
@AccessLimit(seconds = 1, count = 2)
@GetMapping("/index")
public Object index() {
return "success";
}
}
</code>Testing
When accessing the endpoint, normal requests succeed. If more than two requests occur within one second, the response returns an error message indicating the request rate is too high.
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.