How to Implement Rate Limiting Using Redisson in ContiNew Admin
ContiNew Admin provides a declarative, distributed rate-limiting solution built on Redisson that allows developers to protect API endpoints using simple annotations without manual Redis scripting.
The ContiNew Admin open-source project leverages the ContiNew Starter RateLimiter module to deliver robust traffic control across distributed deployments. By integrating Redisson—the feature-rich Redis Java client—the framework offers a token-bucket algorithm implementation that shares state across all application instances. This guide demonstrates how to configure and apply rate limiting using the actual source code from the continew-org/continew-admin repository.
How the Redisson Rate Limiter Works
Redisson RRateLimiter as the Distributed Engine
At the core of the implementation lies Redisson's RRateLimiter, which stores token buckets directly in Redis. This guarantees that every instance of your application shares the same limiter state, enabling true distributed rate limiting across clusters. When a request hits any node, the node queries the central Redis store to check token availability before permitting the method to proceed.
Spring Boot Starter Integration
The continew-starter-ratelimiter dependency (declared in continew-common/pom.xml) auto-registers a Spring Bean that manages RRateLimiter instances. For each unique name defined in the @RateLimiter annotation, the starter creates or retrieves a configured limiter with the specified rate and interval parameters. If no tokens remain, the starter throws a RateLimitException and translates it into a standard API error response.
Prerequisites and Configuration
Maven Dependency
Add the rate limiter starter to your project dependencies. In ContiNew Admin, this is already included in the common module:
<!-- continew-common/pom.xml -->
<dependency>
<groupId>top.continew.starter</groupId>
<artifactId>continew-starter-ratelimiter</artifactId>
</dependency>
This dependency pulls in Redisson client libraries and the annotation-driven rate limiting aspect.
Redisson Client Configuration
Enable and configure Redisson via your Spring Boot YAML configuration. The starter respects standard spring.data.redisson properties:
# application-dev.yml (excerpt)
spring:
data:
redisson:
enabled: true # Activate Redisson auto-configuration
mode: SINGLE # Deployment mode: SINGLE, CLUSTER, MASTER_SLAVE, etc.
The mode parameter supports various Redis deployment topologies, ensuring the rate limiter works correctly whether you run a single Redis node or a clustered environment.
Implementing Rate Limits with @RateLimiter
Basic Annotation Usage
Apply the @RateLimiter annotation to any Spring bean method—typically controller endpoints—to enforce traffic limits. The annotation maps directly to Redisson's token-bucket parameters:
name: The logical limiter name used as the Redis keykey: SpEL expression resolving the rate-limit key (e.g., per-user or per-IP)rate: Number of tokens allowed per intervalinterval+unit: Duration of the interval (e.g., 1 MINUTE)type: OptionalLimitType(IP, USER) for additional granularitymessage: Error message returned when limit is exceeded
Advanced Key Expressions
The key attribute accepts Spring Expression Language (SpEL) expressions, allowing dynamic resolution based on method arguments or context. In continew-server/src/main/java/top/continew/admin/controller/CaptchaController.java, the implementation combines email addresses with configuration properties to create distinct buckets:
// CaptchaController.java excerpt
@GetMapping("/mail")
@RateLimiter(
name = CacheConstants.CAPTCHA_KEY_PREFIX + "MIN",
key = "#email + ':' + T(cn.hutool.extra.spring.SpringUtil).getProperty('captcha.mail.templatePath')",
rate = 2,
interval = 1,
unit = TimeUnit.MINUTES,
message = "获取验证码操作太频繁,请稍后再试")
public R getMailCaptcha(@NotBlank @Email String email, CaptchaVO captchaReq) {
// Business logic executes only if token is available
}
This configuration creates a unique limiter for each email-template combination, preventing abuse while allowing legitimate multi-template usage.
Multiple Limits with @RateLimiters
For layered protection, use the container annotation @RateLimiters to apply several limits simultaneously. The following example from the captcha controller enforces both a strict per-minute limit and a broader per-hour limit:
// CaptchaController.java excerpt
@Operation(summary = "获取邮箱验证码")
@GetMapping("/mail")
@RateLimiters({
@RateLimiter(
name = CacheConstants.CAPTCHA_KEY_PREFIX + "MIN",
key = "#email + ':' + T(cn.hutool.extra.spring.SpringUtil).getProperty('captcha.mail.templatePath')",
rate = 2, interval = 1, unit = TimeUnit.MINUTES,
message = "获取验证码操作太频繁,请稍后再试"),
@RateLimiter(
name = CacheConstants.CAPTCHA_KEY_PREFIX,
key = "#email",
rate = 30, interval = 1, unit = TimeUnit.MINUTES,
type = LimitType.IP,
message = "获取验证码操作太频繁,请稍后再试")
})
public R getMailCaptcha(String email, CaptchaVO captchaReq) {
// Method protected by two independent rate limits
}
The first limiter restricts specific template requests, while the second applies a global IP-based cap across all captcha requests.
Handling Rate Limit Exceptions
When token exhaustion occurs, the starter throws a RateLimitException containing the configured message. The framework automatically converts this to a standardized R response object returned to the client. To customize error handling globally, provide a @ControllerAdvice that catches RateLimitException and formats the response according to your API standards. No additional try-catch blocks are required in annotated methods.
Summary
- Distributed by design: Redisson's
RRateLimiterensures consistent token accounting across all service instances via Redis. - Zero boilerplate: The
continew-starter-ratelimiterdependency handles Redisson client management and limiter lifecycle automatically. - Declarative syntax: Use
@RateLimiteror@RateLimitersannotations with SpEL expressions to define granular, context-aware limits. - Production ready: Supports multiple Redis deployment modes (SINGLE, CLUSTER, MASTER_SLAVE) through standard Spring configuration properties.
Frequently Asked Questions
How does Redisson ensure rate limits work across multiple server instances?
Redisson stores the token bucket state in a centralized Redis database. Each application instance uses the RRateLimiter implementation to query and decrement tokens from this shared store, ensuring that the rate limit counts requests from all nodes collectively rather than per-instance.
What is the difference between the name and key attributes in @RateLimiter?
The name attribute defines the logical limiter identifier used as the base Redis key structure, while the key attribute resolves to a dynamic suffix via SpEL expressions. For example, name="captcha" combined with key="#userId" creates unique limiters per user under the same logical grouping.
Can I implement different rate limits for different user types?
Yes. Use SpEL expressions in the key attribute to differentiate limiters by user characteristics, or apply multiple @RateLimiter annotations via @RateLimiters. Combine this with the type parameter (LimitType.IP or LimitType.USER) to apply distinct policies based on IP address or authenticated user identity.
What happens if the Redis connection fails?
If Redis becomes unavailable, Redisson will throw connection exceptions. The ContiNew Admin starter does not provide fallback mechanisms for rate limiting when Redis is down; the method invocation will fail fast rather than allowing unlimited requests. Ensure Redis high availability through clustering or Sentinel configurations to maintain rate limiting integrity.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →