我是靠谱客的博主 有魅力冷风,最近开发中收集的这篇文章主要介绍springBoot使用guava的令牌桶机制实现限流,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

      guava是谷歌提供的一RateLimiter,指定一个qps的值,请求来需要acquire获取令牌,直到令牌重新填充才得到放行。tryAcquire方法的话,可以指定一个等待时间,并返回一个Boolea值。套框架,我们这里需要用到的是它的限流器:不足之处:所有的请求进来都是调用acquire。无法根据ip或者其他的类型关键字来区分。所以我们引入了缓存,类似HashMap,针对不同的关键字(本文使用方法名)生成不同的限流器。

1、引入配置依赖

低版本没有RateLimiter方法,版本不对时可升一下版本号

<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>18.0</version>
</dependency>

2、注解

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RateLimit {
int NOT_LIMITED = 0;
@AliasFor("qps")
double value() default NOT_LIMITED;
@AliasFor("value")
double qps() default NOT_LIMITED;
/**
* 超时时长
*/
int timeout() default 0;
/**
* 超时时间单位
*/
TimeUnit timeUnit() default TimeUnit.MILLISECONDS;
}

3、切面

@Slf4j
@Aspect
@Component
public class RateLimitAspect {
private static final ConcurrentMap<String, RateLimiter> RATE_LIMITER_CACHE = new ConcurrentHashMap<>(16);
@Pointcut("@annotation(com.example.springbootdemoratelimitguava.annotation.RateLimit)")
public void rateLimit() {
}
@Around("rateLimit()")
public Object pointcut(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
MethodSignature methodSignature = (MethodSignature) proceedingJoinPoint.getSignature();
Method method = methodSignature.getMethod();
RateLimit rateLimit = AnnotationUtils.findAnnotation(method, RateLimit.class);
if (Objects.nonNull(rateLimit) && rateLimit.qps() > RateLimit.NOT_LIMITED) {
double qps = rateLimit.qps();
// 缓存池中是否有对象 没有则初始化刷入
if (Objects.isNull(RATE_LIMITER_CACHE.get(method.getName()))) {
RATE_LIMITER_CACHE.put(method.getName(), RateLimiter.create(qps));
}
log.debug("[{}]的qps设置为:{}", method.getName(), RATE_LIMITER_CACHE.get(method.getName()).getRate());
// 尝试获取令牌
if (Objects.nonNull(RATE_LIMITER_CACHE.get(method.getName())) && !RATE_LIMITER_CACHE.get(method.getName()).tryAcquire(rateLimit.timeout(), rateLimit.timeUnit())) {
throw new RuntimeException("请求次数过多,请稍后再试");
}
}
return proceedingJoinPoint.proceed();
}
}

4、全局异常捕捉

@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(RuntimeException.class)
public Dict handler(RuntimeException exception) {
return Dict.create().set("msg", exception.getMessage());
}
}

5、测试方法

@RestController
@RequestMapping("/test")
@Slf4j
public class TestController {
@RateLimit(value = 1.0, timeout = 300)
@GetMapping("/test1")
public Dict test1() {
log.info("【test1】被执行了。。。。。");
return Dict.create().set("msg", "hello,world!").set("description", "别想一直看到我,不信你快速刷新看看~");
}
@GetMapping("/test2")
public Dict test2() {
log.info("【test2】被执行了。。。。。");
return Dict.create().set("msg", "hello,world!").set("description", "我一直都在,卟离卟弃");
}
@RateLimit(value = 2.0, timeout = 300)
@GetMapping("/test3")
public Dict test3() {
log.info("【test3】被执行了。。。。。");
return Dict.create().set("msg", "hello,world!").set("description", "别想一直看到我,不信你快速刷新看看~");
}
}

最后

以上就是有魅力冷风为你收集整理的springBoot使用guava的令牌桶机制实现限流的全部内容,希望文章能够帮你解决springBoot使用guava的令牌桶机制实现限流所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(35)

评论列表共有 0 条评论

立即
投稿
返回
顶部