springboot实现一个控制器,控制器是get请求,名字show,用注解的方式实现该接口每分钟只能访问5次
要实现这个功能,您可以使用Spring Boot的@RestController
和@GetMapping
注解创建一个名为show
的GET请求控制器。然后,您可以使用RateLimiter
来限制每分钟访问次数。这里是一个简单的示例:
首先,添加Guava
依赖到您的pom.xml
文件中:
<dependencies>
<!-- other dependencies -->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>30.1-jre</version>
</dependency>
</dependencies>
然后,创建一个名为RateLimiterAspect
的切面类,用于限制每分钟访问次数:
import com.google.common.util.concurrent.RateLimiter;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class RateLimiterAspect {
private final RateLimiter rateLimiter = RateLimiter.create(5.0 / 60.0); // 5 permits per minute
@Before("@annotation(com.example.demo.RateLimited)")
public void rateLimit() {
rateLimiter.acquire();
}
}
接下来,创建一个自定义注解RateLimited
:
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface RateLimited {
}
最后,创建一个名为show
的GET请求控制器,并使用@RateLimited
注解限制每分钟访问次数:
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ShowController {
@RateLimited
@GetMapping("/show")
public String show() {
return "Hello, this is the show endpoint!";
}
}
现在,当您尝试访问/show
端点时,每分钟只能访问5次。请注意,这个简单的示例没有处理并发访问的情况,如果您需要在高并发环境下使用,请考虑使用更复杂的限流策略。
不同的接口每分钟访问次数不一样
为了实现不同接口每分钟访问次数不一样的限制,您可以在自定义的RateLimited
注解中添加一个属性,用于指定每分钟的访问次数。然后,在RateLimiterAspect
中为每个接口创建一个单独的RateLimiter
实例。
首先,修改RateLimited
注解,添加一个名为value
的属性:
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface RateLimited {
double value();
}
接下来,修改RateLimiterAspect
类,为每个接口创建一个单独的RateLimiter
实例:
import com.google.common.util.concurrent.RateLimiter;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@Aspect
@Component
public class RateLimiterAspect {
private final Map<String, RateLimiter> rateLimiterMap = new ConcurrentHashMap<>();
@Before("@annotation(com.example.demo.RateLimited)")
public void rateLimit(JoinPoint joinPoint) {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
RateLimited rateLimited = method.getAnnotation(RateLimited.class);
double permitsPerMinute = rateLimited.value();
RateLimiter rateLimiter = rateLimiterMap.computeIfAbsent(method.getName(), k -> RateLimiter.create(permitsPerMinute / 60.0));
rateLimiter.acquire();
}
}
现在,您可以在不同的接口上使用@RateLimited
注解,并指定每分钟的访问次数。例如:
@RestController
public class MyController {
@RateLimited(5)
@GetMapping("/show1")
public String show1() {
return "Hello, this is the show1 endpoint!";
}
@RateLimited(10)
@GetMapping("/show2")
public String show2() {
return "Hello, this is the show2 endpoint!";
}
}
在这个示例中,show1
接口每分钟只能访问5次,而show2
接口每分钟可以访问10次。
不用goole这个依赖com.google.guava
如果您不想使用Guava库,可以使用Java的Semaphore
类来实现类似的功能。以下是一个不使用Guava的实现:
首先,修改RateLimiterAspect
类,使用Semaphore
替代RateLimiter
:
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
@Aspect
@Component
public class RateLimiterAspect {
private final Map<String, Semaphore> semaphoreMap = new ConcurrentHashMap<>();
@Before("@annotation(com.example.demo.RateLimited)")
public void rateLimit(JoinPoint joinPoint) throws InterruptedException {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
RateLimited rateLimited = method.getAnnotation(RateLimited.class);
int permitsPerMinute = (int) rateLimited.value();
Semaphore semaphore = semaphoreMap.computeIfAbsent(method.getName(), k -> new Semaphore(permitsPerMinute));
semaphore.tryAcquire(1, TimeUnit.MINUTES);
}
}
请注意,这个实现可能不如Guava的RateLimiter
精确,因为它使用的是Semaphore
,而不是基于令牌桶算法的RateLimiter
。但是,这个实现可以在不使用Guava的情况下为您提供基本的限流功能。
powered by kaifamiao