java控制访问接口次数
1、注解类
/** * 默认1s以内可访问10次
* 当limit <= 2时,time秒以内可访问2次
* 当limit > 2时,time秒以内可访问limit次
*/
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface RequestLimit {
int limit ()default 10;
int time() default 1;
}
2、注解切面类
@Aspect@Component
@Slf4j
public class RequestLimitAspect {
@Autowired
HttpServletRequest request;
@Autowired
RedisUtils redisUtils;
/**
* 被此注解标明的方法会被代理
*/
@Pointcut("@annotation(com.example.currentlimiting.demo.annotation.RequestLimit)")
public void limitPointCut() {
}
/**
* 环绕通知拿到方法上RequestLimit注解的2个属性值 以作比较
*/
@Around("limitPointCut()")
public Object around(ProceedingJoinPoint point) throws Throwable {
MethodSignature signature = (MethodSignature) point.getSignature();
RequestLimit requestLimit = signature.getMethod().getAnnotation(RequestLimit.class);
if (requestLimit != null) {
String key = getCacheKey();
int limit = requestLimit.limit();
int time = requestLimit.time();
limit = limit > 1? (limit - 1):1;
time = time > 0? time: 1;
cacheOrRefuse(key, limit, time);
}
return point.proceed();
}
/**
* ip+url作为资源的key
*/
private String getCacheKey() {
return IPUtil.getIpAddress(request) + ":" + request.getRequestURI();
}
/**
* 达到次数 停止服务 Or 访问次数+1
*/
private void cacheOrRefuse(String key, int limit, int time) {
if (redisUtils.hasKey(key)) {
String count = redisUtils.get(key).get();
int countRequest = Integer.parseInt(count);
if (countRequest > limit) {
throw new AppBusinessException("MAS-00-50001", HttpStatus.BAD_REQUEST.value(), HttpStatus.BAD_REQUEST.getReasonPhrase());
} else {
redisUtils.incr(key, 1);
}
} else {
redisUtils.incrWithExpireTime(key, time);
}
}
}
3、测试接口
@RestController@Slf4j
public class TestController {
/**
* 1s内只接受3个请求
* @return
*/
@RequestLimit(time = 1, limit = 3)
@GetMapping(value = "/hello", produces = "application/json;charset=UTF-8")
public ResponseEntity<String> hello() {
return ResponseEntity.ok(">>>1s内只接受3个请求:" + System.currentTimeMillis());
}
}
测试结果:
B、 RateLimiter实现控制访问接口次数
导jar包
<dependency> <groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>23.0</version>
</dependency>
1、RateLimit注解
@Inherited@Documented
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RateLimit {
//默认每秒放入桶中的token
double limit() default 20;
}
2、RateLimit注解切面RateLimitAspect
@Slf4j@Component
@Scope
@Aspect
public class RateLimitAspect {
/**
* 用来存放不同接口的RateLimiter(key为接口名称,value为RateLimiter)
*/
private ConcurrentHashMap<String, RateLimiter> map = new ConcurrentHashMap<>();
private RateLimiter rateLimiter;
@Resource
private HttpServletResponse response;
@Pointcut("@annotation(com.example.currentlimiting.demo.annotation.RateLimit)")
public void serviceLimit() {
}
@Around("serviceLimit()")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
Object result = null;
//获取拦截的方法名
Signature sig = joinPoint.getSignature();
//获取拦截的方法名
MethodSignature msig = (MethodSignature) sig;
//返回被织入增加处理目标对象
Object target = joinPoint.getTarget();
//为了获取注解信息
Method currentMethod = target.getClass().getMethod(msig.getName(), msig.getParameterTypes());
//获取注解信息
RateLimit annotation = currentMethod.getAnnotation(RateLimit.class);
//获取注解每秒加入桶中的token
double limit = annotation.limit();
// 注解所在方法名区分不同的限流策略
String functionName = msig.getName();
//获取rateLimiter
if (map.containsKey(functionName)) {
rateLimiter = map.get(functionName);
} else {
map.put(functionName, RateLimiter.create(limit));
rateLimiter = map.get(functionName);
}
if (rateLimiter.tryAcquire()) {
//执行方法
result = joinPoint.proceed();
} else {
throw new AppBusinessException(HttpStatus.FORBIDDEN.getReasonPhrase(), HttpStatus.FORBIDDEN.value(), ">>>超过限制请求数,服务器拒绝了请求");
}
return result;
}
}
3、测试接口
/** * 每秒内只接受3个请求
* @return
*/
@RateLimit(limit = 3)
@GetMapping(value = "/hello", produces = "application/json;charset=UTF-8")
public ResponseEntity<String> hello() {
return ResponseEntity.ok("每秒内只接受3个请求:" + System.currentTimeMillis());
}
测试结果:
代码:https://gitee.com/lion123/springboot-current-limiting-demo
以上是 java控制访问接口次数 的全部内容, 来源链接: utcz.com/z/513258.html