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
