使用AOP切面来实现接口访问频率限制。具体实现方法如下:
创建一个注解@LimitRequestFrequency,用于标记需要进行访问频率限制的接口方法。该注解需要包含一个属性value,表示每秒钟允许的最大访问次数。
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface LimitRequestFrequency {
int value() default 1;
}
创建一个切面类RequestFrequencyLimitAspect,用于拦截被@LimitRequestFrequency注解标记的接口方法。在该切面类中,我们需要使用ConcurrentHashMap存储每个请求的访问次数和时间戳,并根据当前时间与上一次请求的时间间隔判断是否允许该请求。如果允许该请求,则将访问次数加1,并更新时间戳;否则,抛出TooManyRequestsException异常。
@Aspect
@Component
public class RequestFrequencyLimitAspect {
private ConcurrentHashMap<String, Long> requestCountMap = new ConcurrentHashMap<>();
@Around("@annotation(limitRequestFrequency)")
public Object limitRequestFrequency(ProceedingJoinPoint joinPoint, LimitRequestFrequency limitRequestFrequency) throws Throwable {
HttpServletRequest request = getRequest(joinPoint);
String ip = request.getRemoteAddr();
String uri = request.getRequestURI();
String key = ip + ":" + uri;
Long lastRequestTime = requestCountMap.get(key);
long now = System.currentTimeMillis();
if (lastRequestTime != null && (now - lastRequestTime) < 1000) {
throw new TooManyRequestsException("Too many requests");
}
requestCountMap.put(key, now);
Object result = joinPoint.proceed();
return result;
}
private HttpServletRequest getRequest(ProceedingJoinPoint joinPoint) {
for (Object arg : joinPoint.getArgs()) {
if (arg instanceof HttpServletRequest) {
return (HttpServletRequest) arg;
}
}
throw new IllegalArgumentException("HttpServletRequest argument not found");
}
}
在控制器中使用@LimitRequestFrequency注解标记需要进行访问频率限制的接口方法。在注解中指定每秒钟允许的最大访问次数。
@RestController
public class HelloController {
@GetMapping("/hello")
@LimitRequestFrequency(1)
public String hello() {
return "Hello, World!";
}
}
在以上实现中,我们使用AOP切面来实现了基于注解的接口访问频率限制。需要注意的是,如果有多个请求同时访问同一个接口,可能会出现线程安全问题,需要进行处理。同时,我们也需要编写TooManyRequestsException异常类,用于在访问频率超限时抛出异常。