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

回到顶部