专注于 JetBrains IDEA 全家桶,永久激活,教程
持续更新 PyCharm,IDEA,WebStorm,PhpStorm,DataGrip,RubyMine,CLion,AppCode 永久激活教程

java控制访问接口次数(接口限流)

A、注解方式控制访问接口次数

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() {
    }

    @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();
    }

    private String getCacheKey() {
        return IPUtil.getIpAddress(request) + ":" + request.getRequestURI();
    }

    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());
    }
}

测试结果:

84_1.png

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());
}

测试结果:

84_2.png

代码:https://gitee.com/lion123/springboot-current-limiting-demo

C、spring-cloud-alibaba-sentinel-gateway和spring-cloud-starter-gateway限流

D、消息队列限流,请求到来先将请求放进消息队列,再在消息队列中使用这些请求数据来请求业务接口。

文章永久链接:https://tech.souyunku.com/25003

未经允许不得转载:搜云库技术团队 » java控制访问接口次数(接口限流)

JetBrains 全家桶,激活、破解、教程

提供 JetBrains 全家桶激活码、注册码、破解补丁下载及详细激活教程,支持 IntelliJ IDEA、PyCharm、WebStorm 等工具的永久激活。无论是破解教程,还是最新激活码,均可免费获得,帮助开发者解决常见激活问题,确保轻松破解并快速使用 JetBrains 软件。获取免费的破解补丁和激活码,快速解决激活难题,全面覆盖 2024/2025 版本!

联系我们联系我们