SpringbootGuava+AOP接口限流
1.Springboot Guava工具类RateLimiter+AOP限流
1. 添加依赖
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>30.1-jre</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
2. 创建注解
/**
* @author devcxl
*/
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Limit {
/**
* 拦截标识
*
* @return
*/
String key() default "";
/**
* 次数
*
* @return
*/
int max() default 1;
/**
* 最大等待时间
*
* @return
*/
int timeout() default 5;
/**
* 最大等待时间时间单位
*
* @return
*/
TimeUnit timeUnit() default TimeUnit.SECONDS;
/**
* 提示
*
* @return
*/
String msg() default "系统繁忙,请稍后再试.";
}
3. AOP实现
@Slf4j
@Aspect
@Component
public class LimitAspect {
/**
* 内存中记录限制
*/
private Map<String, RateLimiter> limitMap = Maps.newConcurrentMap();
@Around("@annotation(cn.devcxl.common.annotation.guava.Limit)")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable{
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
Limit limit = method.getAnnotation(Limit.class);
if (limit != null) {
String key=limit.key();
RateLimiter rateLimiter = null;
//不存在直接新建
if (!limitMap.containsKey(key)) {
rateLimiter = RateLimiter.create(limit.max());
limitMap.put(key, rateLimiter);
log.info("Limit:{},max:{}",key,limit.max());
}
rateLimiter = limitMap.get(key);
boolean acquire = rateLimiter.tryAcquire(limit.timeout(), limit.timeUnit());
// 拿不到直接抛异常
if (!acquire) {
// RuntimeException 可以改为自定义异常 可在全局异常捕获中处理并返回给前端
throw new RuntimeException(limit.msg());
}
}
return joinPoint.proceed();
}
}
4. 使用
@Slf4j
@RestController
@RequestMapping("/test")
public class TestController {
@GetMapping("/limit")
@Limit(key = "test1", max = 1, timeout = 300, timeunit = TimeUnit.MILLISECONDS, msg = "系统繁忙,请稍后再试。")
public Resp<String> test1() {
log.info("test1");
return Resp.ok();
}
}