注解+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等反向代理工具实现分布式限流。