php与mysql程序设计第5版高效的
95.1元
包邮
(需用券)
去购买 >
需求:单位时间内,比如1s,限制某个接口的调用次数。
RateLimiter
RateLimiter基于令牌桶算法,有一个令牌桶,单位时间内令牌会以恒定的数量(即令牌的加入速度)加入到令牌桶中,所有请求都需要获取令牌才可正常访问。当令牌桶中没有令牌可取的时候,则拒绝请求。
定义一个接口:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RateLimit {
//每秒限制次数
double limit() default 1;
}
定义一个切面:
@Slf4j
@Component
@Aspect
public class RateLimitAspect {
private static final ConcurrentMap rateLimiterCache = new ConcurrentHashMap<>();
@Pointcut("@annotation(com.example.demo.RateLimit)")
public void rateLimit() {
}
@Around("rateLimit()")
public Object pointcut(ProceedingJoinPoint joinPoint) throws Throwable {
Object obj = null;
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
RateLimit rateLimit = AnnotationUtils.findAnnotation(method, RateLimit.class);
if (rateLimit != null) {
if (rateLimiterCache.get(method.getName()) == null) {
rateLimiterCache.put(method.getName(), RateLimiter.create(rateLimit.limit()));
}
RateLimiter rateLimiter = rateLimiterCache.get(method.getName());
if (rateLimiter != null) {
if (!rateLimiter.tryAcquire()) {
log.info("=====完了没抢到...=====");
} else {
log.info("=====我抢到了!!=====");
obj = joinPoint.proceed();
}
}
}
return obj;
}
}
controller:
@Slf4j
@RestController
public class TestController {
@RateLimit(limit = 5)
@GetMapping("/test")
public String test() {
return "请求成功";
}
}
Redis
利用了Redis的自增和过期时间
@Slf4j
@RestController
public class TestController {
private int countLimit = 5;
private int timeLimit = 1;
@Autowired
StringRedisTemplate stringRedisTemplate;
@GetMapping("/test")
public String test(String key) {
if (stringRedisTemplate.hasKey(key)) {
long count = stringRedisTemplate.boundValueOps(key).increment(1);
if (count > countLimit) {
log.info("请求过于繁忙");
}
} else {
stringRedisTemplate.opsForValue().set(key, "1", timeLimit, TimeUnit.SECONDS);
}
return "请求成功";
}
}
java 11官方入门(第8版)教材
79.84元
包邮
(需用券)
去购买 >