在Spring Boot中实现接口限流,可以通过创建一个自定义注解来指定限流规则,然后用AOP(面向切面编程)来拦截注解标识的方法。以下是详细的例子,演示如何使用Guava的RateLimiter
来实现一个简单的限流方案一步一步实现的过程:
- 引入相关依赖
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>30.1-jre</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.7</version>
</dependency>
- 创建自定义限流注解(
RateLimit
)
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD) // 方法注解
@Retention(RetentionPolicy.RUNTIME) // 运行时保留
public @interface RateLimit {
double permitsPerSecond() default 1.0; // 每秒生成的令牌数
long timeout() default 0; // 获取令牌等待时间,默认0,不等待
}
- 使用AOP创建切面包含限流逻辑
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import com.google.common.util.concurrent.RateLimiter;
import java.util.concurrent.ConcurrentHashMap;
@Aspect
@Component
public class RateLimitAspect {
private ConcurrentHashMap<String, RateLimiter> limiters = new ConcurrentHashMap<>();
@Pointcut("@annotation(com.yourpackage.RateLimit)")
public void rateLimit() {
}
@Around("rateLimit()")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
RateLimit rateLimit = signature.getMethod().getAnnotation(RateLimit.class);
if (rateLimit != null) {
double permitsPerSecond = rateLimit.permitsPerSecond();
long timeout = rateLimit.timeout();
// 构建或获取RateLimiter
RateLimiter rateLimiter = limiters.computeIfAbsent(signature.toLongString(), (key) -> RateLimiter.create(permitsPerSecond));
// 获取令牌
boolean acquired = timeout == 0L ? rateLimiter.tryAcquire() : rateLimiter.tryAcquire(timeout, TimeUnit.MILLISECONDS);
if (!acquired) {
throw new RuntimeException("System is too busy, please try again later.");
}
}
return joinPoint.proceed();
}
}
如需更复杂的限流策略,可考虑算法如令牌桶(Guava的RateLimiter
已采用)、漏桶、固定窗口、滑动窗口或者是使用 Redis + Lua脚本来做分布式限流。
- 在对应的方法上使用你的自定义注解
@RestController
public class RateLimitController {
@RequestMapping("/ratelimitTest")
@RateLimit(permitsPerSecond = 1)
public String rateLimitTest() {
return "Request was allowed.";
}
}
- 启动应用
配置好以上内容后,启动Spring Boot应用,通过实际请求来测试限流效果。当请求的速率超过注解中设定的permitsPerSecond
值时,就会抛出异常或返回限流提示。
6. 总结
请注意这仅是一个简单的示例。负载不均和配置更新可能会导致此限流策略在更复杂场景下效果有限。在生产级别应用中,您可能需要实现更复杂的策略,如集成 Redis 做分布式限流。