Redis 实现多规则限流的思考与实践( 三 )

编写 AOP 拦截@Autowiredprivate RedisTemplate<String, Object> redisTemplate;@Autowiredprivate RedisScript<Boolean> limitScript;/** * 限流 * XXX 对限流要求比较高,可以使用在 Redis中对规则进行存储校验 或者使用中间件 * * @param joinPointjoinPoint * @param rateLimiter 限流注解 */@Before(value = https://www.isolves.com/it/sjk/Redis/2024-01-03/"@annotation(rateLimiter)")public void boBefore(JoinPoint joinPoint, RateLimiter rateLimiter) {// 1. 生成 keyString key = getCombineKey(rateLimiter, joinPoint);try {// 2. 执行脚本返回是否限流Boolean flag = redisTemplate.execute(limitScript,ListUtil.of(key, String.valueOf(System.currentTimeMillis())),(Object[]) getRules(rateLimiter));// 3. 判断是否限流if (Boolean.TRUE.equals(flag)) {log.error("ip: '{}' 拦截到一个请求 RedisKey: '{}'",IpUtil.getIpAddr(((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest()),key);throw new ServiceException(rateLimiter.message());}} catch (ServiceException e) {throw e;} catch (Exception e) {e.printStackTrace();}}/** * 获取规则 * * @param rateLimiter 获取其中规则信息 * @return */private Long[] getRules(RateLimiter rateLimiter) {int capacity = rateLimiter.rules().length << 1;// 1. 构建 argsLong[] args = new Long[rateLimiter.preventDuplicate() ? capacity + 2 : capacity];// 3. 记录数组元素int index = 0;// 2. 判断是否需要添加防重复提交到redis进行校验if (rateLimiter.preventDuplicate()) {RateRule preventRateRule = rateLimiter.preventDuplicateRule();args[index++] = preventRateRule.count();args[index++] = preventRateRule.timeUnit().toMillis(preventRateRule.time());}RateRule[] rules = rateLimiter.rules();for (RateRule rule : rules) {args[index++] = rule.count();args[index++] = rule.timeUnit().toMillis(rule.time());}return args;}以上 , 欢迎大家提出意见 。




推荐阅读