限流(SpringBoot + AOP)

Google开源工具包Guava提供了限流工具类RateLimiter,该类基于令牌桶算法实现流量限制
第一步:引入guava依赖包
<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>30.1-jre</version>
</dependency>
第二步:给接口加上限流逻辑
@RestController
@RequestMapping("/test2")
public class AopTextController {

    /**
     * 限流策略 : 1秒钟2个请求
     */
    private final RateLimiter limiter = RateLimiter.create(2.0);

    @RequestMapping("/limit1")
    public String limit1(){
    	//500毫秒内,没拿到令牌,就直接进入服务降级
        boolean bool = limiter.tryAcquire(500, TimeUnit.MILLISECONDS);
        if(!bool){
            System.out.println("系统繁忙,请稍后再试.");
            return "系统繁忙,请稍后再试.";
        }
        System.out.println("limit1请求成功!!!");
        return "请求成功";
    }

}

输出结果:
在这里插入图片描述

真是项目中不这样用,每个接口都需要手动给其加上tryAcquire(),业务代码和限流代码混在一起,而且明显违背了DRY原则。
所以优化方式:自定义注解+AOP实现接口限流。

第一步:引入AOP依赖
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-aop</artifactId>
</dependency>
第二步:自定义限流注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @interface CacheableTest {

    /**
     * 资源的key,唯一
     * 作用:不同的接口,不同的流量控制
     */
    String key();

    /**
     * 一秒最多的访问限制次数
     */
    double permitsPerSecond () ;

    /**
     * 获取令牌最大等待时间,单位毫秒
     */
    long timeout();

    /**
     * 得不到令牌的提示语
     */
    String msg() default "系统繁忙,请稍后再试.";


}
第三步:使用AOP切面拦截限流注解
@Component
@Aspect
public class TestAop {

    /**
     * 不同的接口,不同的流量控制
     * map的key为 Limiter.key
     * RateLimiter 限流策略 : 1秒钟n个请求
     */
    private final Map<String, RateLimiter> limitMap = new HashMap<>();

    @Pointcut("@annotation(com.wang.aop.CacheableTest)")    //第一个星号指返回值类型为任意
    private void pointCut(){};


    @Around(value = "pointCut()")
    public Object logBefore(JoinPoint joinpoint) throws Throwable {
        //获取注解对象
        CacheableTest cacheableTest = ((MethodSignature)joinpoint.getSignature()).getMethod().getAnnotation(CacheableTest.class);
        if (cacheableTest != null){
            RateLimiter rateLimiter = limitMap.get(cacheableTest.key());
            if (rateLimiter == null){
                rateLimiter = RateLimiter.create(cacheableTest.permitsPerSecond()); //限流策略 : 1秒钟2个请求
                limitMap.put(cacheableTest.key(), rateLimiter);
            }
            boolean bool = rateLimiter.tryAcquire(cacheableTest.timeout(), TimeUnit.MILLISECONDS); //xx毫秒内,没拿到令牌,就直接进入服务降级
            if(!bool){
                //被限流
                System.out.println(cacheableTest.msg());
                return null;
            }
        }

        ProceedingJoinPoint point = (ProceedingJoinPoint) joinpoint;

        return point.proceed();
    }

}
第四步:调用接口方法:
@RestController
@RequestMapping("/test2")
public class AopTextController {

    @RequestMapping("/limit1")
    @CacheableTest(key="limit1", permitsPerSecond=2.0, timeout=500)
    public String limit1(){

        System.out.println("请求成功");
        return "请求成功";
    }

}

打印结果:
在这里插入图片描述

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值