注解+redis实现接口限流。

204 阅读1分钟

注解+Redis来限制接口的调用频率。以下是一个使用注解+Redis实现的接口限流示例代码:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.core.annotation.Order;

@Component
@Aspect
@Order(1)
public class RequestLimitAspect {

    @Autowired
    private RedisTemplate<String, Serializable> redisTemplate;
    private AtomicInteger reqCount = new AtomicInteger(0);

    @Around("execution(* com.example.demo.controller..*(..)) && @annotation(limit)")
    public Object requestLimit(ProceedingJoinPoint joinPoint, RequestLimit limit) throws Throwable {
        Object[] args = joinPoint.getArgs();
        String key = limit.key();
        int seconds = limit.seconds();
        int maxCount = limit.maxCount();
        String redisKey = "request_limit_" + key;
        ValueOperations<String, Serializable> opsForValue = redisTemplate.opsForValue();
        Integer count = (Integer) opsForValue.get(redisKey);
        if (count == null) {
            opsForValue.set(redisKey, new AtomicInteger(0));
            redisTemplate.expire(redisKey, seconds, TimeUnit.SECONDS);
        } else if (count >= maxCount) {
            throw new Exception("接口访问频率超出限制!");
        } else {
            opsForValue.increment(redisKey);
        }
        reqCount.incrementAndGet();
        try {
            Object result = joinPoint.proceed(args);
            return result;
        } finally {
            if (reqCount.decrementAndGet() < 0) {
                reqCount.set(0);
            }
            opsForValue.decrement(redisKey);
        }
    }
}

**

这段代码中,我们定义了一个RequestLimitAspect切面,用来实现接口限流。在接口上标注@RequestLimit注解,可以指定每个接口在一段时间内最多被访问的次数。在切面中,我们通过Redis记录每个接口的访问次数,并在达到访问限制时抛出异常,防止过度调用导致系统崩溃。

需要注意的是,这种基于注解的限流方式虽然简单易用,但也有其局限性。具体而言,这种方法只是针对单个应用程序进程进行限流,对于跨进程或跨服务器的并发请求,可能无法起到很好的效果。 为了解决这个问题,可以考虑使用基于Redis的全局限流方案,或者结合Nginx等反向代理工具实现分布式限流。