SpringBoot注解限制接口访问次数

1.首先,需要在pom.xml文件中添加以下依赖,以使用Spring AOP和Ehcache缓存

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
    <groupId>net.sf.ehcache</groupId>
    <artifactId>ehcache</artifactId>
    <version>2.10.6</version>
</dependency>

2.创建一个自定义注解@ApiLimit,用于标记需要限制访问次数的接口

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RateLimit {
    int limit() default 10;
    long interval() default 1000;
}

3.创建一个切面类RateLimitAspect,用于实现限制访问次数的逻辑。该切面类使用@Aspect和@Component注解进行标记,表示它是一个切面并且可以被Spring容器管理。

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Aspect
@Component
public class RateLimitAspect {
    private Map<String, Long> requestCounts = new HashMap<>();

    @Before("@annotation(rateLimit)")
    public void checkRateLimit(JoinPoint joinPoint, RateLimit rateLimit) throws InterruptedException {
        String methodName = joinPoint.getSignature().toShortString();
        long limit = rateLimit.limit();
        long interval = rateLimit.interval();

        synchronized (requestCounts) {
            long currentTime = System.currentTimeMillis();
            if (requestCounts.containsKey(methodName)) {
                long lastRequestTime = requestCounts.get(methodName);
                long elapsedTime = currentTime - lastRequestTime;
                if (elapsedTime < interval) {
                    if (requestCounts.getOrDefault(methodName, 0L) >= limit) {
                        TimeUnit.MILLISECONDS.sleep(interval - elapsedTime);
                        requestCounts.put(methodName, currentTime);
                        return;
                    }
                }
            }
            requestCounts.put(methodName, currentTime);
        }
    }
}

在RateLimitAspect类中,我们使用@Before注解来指定在目标方法执行之前执行切面逻辑。通过@annotation(rateLimit)指定了切点,它表示切入带有RateLimit注解的方法。

在checkRateLimit方法中,我们首先获取目标方法的名称,并从requestCounts中查找该方法的上次请求时间。如果上次请求时间存在且与当前时间间隔不超过指定的interval,则判断请求次数是否超过了限制的limit。如果超过了限制,则通过TimeUnit.MILLISECONDS.sleep(interval - elapsedTime)暂停当前线程,以保持请求速率在限制范围内。

最后,我们将当前请求的时间存储到requestCounts中,以便下一次请求时使用。

4.使用以上代码,只需要在需要限制访问次数的接口方法上添加@RateLimit注解。

@RestController
public class MyController {
    @GetMapping("/myApi")
    @RateLimit(limit = 5, interval = 1000) // 每秒最多允许5次访问
    public String myApi() {
        // 处理接口逻辑
        return "Hello World!";
    }
}

注:以上代码只是一个简单示例,仅考虑了单机环境下的请求限制。在实际应用中,可能需要考虑分布式环境下的请求限制,以及更复杂的限流策略。可以根据实际需求进行相应的扩展和优化。

你可能感兴趣的:(spring,boot,java,spring)