redisson-注解限流

redisson-注解限流

实现功能

  • 注解实现依赖
  • 注解可以重复添加且条件满足即生效

引入 依赖

<dependency>
    <groupId>org.redisson</groupId>
    <artifactId>redisson-spring-boot-starter</artifactId>
    <version>3.23.2</version>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

定义注解

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(RequestLimiters.class)
@Documented
public @interface RequestLimiter {

    String key();

    /**
     * 默认:单机
     * @return
     */
    RateType type() default RateType.PER_CLIENT;

    /**
     * 间隔速率
     *
     * @return
     */
    long rate() default 100;

    /**
     * 间隔
     *
     * @return
     */
    long interval() default 1000;

    RateIntervalUnit timeUnit() default RateIntervalUnit.MILLISECONDS;
}


@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RequestLimiters {
    RequestLimiter[] value();
}

定义切面

public class RequestLimiterAspect {

    private RedissonClient redissonClient;

    public RequestLimiterAspect(RedissonClient redissonClient) {
        this.redissonClient = redissonClient;
    }

//    @Pointcut("@annotation(requestLimiter)")
//    public void pointcut(RequestLimiter requestLimiter) {
//
//    }
//
//    @Around(value = "pointcut(requestLimiter)", argNames = "pjp,requestLimiter")
//    public Object around(ProceedingJoinPoint pjp, RequestLimiter requestLimiter) throws Throwable {
//        RRateLimiter limiter = getRateLimiter(requestLimiter);
//        if (limiter.tryAcquire(1)) {
//            return pjp.proceed();
//        } else {
//            throw new RateLimitException("too many requests");
//        }
//    }

    @Pointcut("@annotation(com.example.redis.frame.RequestLimiters)||@annotation(com.example.redis.frame.RequestLimiter)")
    public void pointcuts() {

    }

    @Around(value = "pointcuts()", argNames = "pjp")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        MethodSignature signature = (MethodSignature) pjp.getSignature();
        RequestLimiter[] annotations = signature.getMethod().getAnnotationsByType(RequestLimiter.class);
        //按照时间排序 间隔越长,优先匹配!!
        //所以加重复注解时,需要把duration 长的时间放在最上面
        for (RequestLimiter requestLimiter : annotations) {
            tryRateLimit(requestLimiter);
        }
        return pjp.proceed();
    }

    private void tryRateLimit(RequestLimiter requestLimiter) {
        RRateLimiter limiter = getRateLimiter(requestLimiter);
        System.out.println(requestLimiter.key() + " permit: " + limiter.availablePermits());
        if (!limiter.tryAcquire(1)) {
            //只要 有一个不满足,就失败
            throw new RateLimitException("too many requests: " + requestLimiter.key());
        }
    }

    private RRateLimiter getRateLimiter(RequestLimiter requestLimiter) {
        RRateLimiter rateLimiter = redissonClient.getRateLimiter(requestLimiter.key());
        rateLimiter.trySetRate(requestLimiter.type(), requestLimiter.rate(), requestLimiter.interval(), requestLimiter.timeUnit());
        return rateLimiter;
    }

}

配置

@Configuration
public class ReteLimitConfiguration {

    @Autowired
    private RedissonClient redissonClient;

    @Bean
    public RequestLimiterAspect aspect(){
        return new RequestLimiterAspect(redissonClient);
    }
}


public class RateLimitException extends RuntimeException{

    public RateLimitException(String message) {
        super(message);
    }
}

@RestControllerAdvice
public class GlobalExceptionAdvice {

    @ResponseBody
    @ExceptionHandler(value = RateLimitException.class)
    public Map errorHandler(RateLimitException ex) {
        Map map = new HashMap();
        map.put("code", 100);
        map.put("msg", ex.getMessage());
        return map;
    }

}

测试

@RestController
public class IndexApi {

    @Autowired
    private StringRedisTemplate redisTemplate;

    @RequestLimiter(key = "test",rate = 1,interval = 10,timeUnit = RateIntervalUnit.SECONDS)
    @GetMapping("/set")
    public String set(@RequestParam String key, @RequestParam String val) {
        redisTemplate.opsForValue().set(key, val);
        return "success";
    }
    /**
     * duration 越长,放在上面,就像 test3在test4上面
     * @param key
     * @param val
     * @return
     */
    @RequestLimiter(key = "test3",rate = 3,interval = 20,timeUnit = RateIntervalUnit.SECONDS)
    @RequestLimiter(key = "test4",rate = 2,interval = 10,timeUnit = RateIntervalUnit.SECONDS)
    @GetMapping("/set2")
    public String set2(@RequestParam String key, @RequestParam String val) {
        redisTemplate.opsForValue().set(key, val);
        return "success";
    }

}

不出意外,set2接口先出现

{
    "msg": "too many requests: test4",
    "code": 100
}
# 再出现
{
    "msg": "too many requests: test3",
    "code": 100
}

主要是试试重复注解的使用

good luck!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值