springboot限流注解

我们在工作中 有些接口访问量过大 为了保证服务的正常运行可以增加限流

第一步 引入aop和redis

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
		<dependency>
   			<groupId>org.springframework.boot</groupId>
    		<artifactId>spring-boot-starter-data-redis</artifactId>
		</dependency>

第二步 注解实现


@Target(value = ElementType.METHOD)
@Retention(value = RetentionPolicy.RUNTIME)
public @interface Limit {
    /**
     * 资源的key,唯一
     * 作用:不同的接口,不同的流量控制
     */
    String key() default "";

    /**
     * 最大访问限制次数
     */
    double permitsPerSecond();

    /**
     * 得不到令牌的提示语
     */
    String msg() default "访问过多,请稍后再试.";
}

第三步 编写aop切面实现限流

@Slf4j
@Aspect
@Component
public class RateLimiterAspect {

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Around("@annotation(com.nms.common.utils.Limit)")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        Limit limit = method.getAnnotation(Limit.class);
        if (limit != null) {
            String key = "rate_limit:" + limit.key();
            // 获取当前计数
            String countStr = stringRedisTemplate.opsForValue().get(key);
            long count = countStr == null ? 0 : Long.parseLong(countStr);
            if (count >= limit.permitsPerSecond()) {
                log.info("限流生效 - 方法: {}, key: {}", method.getName(), key);
                throw new ServiceException(limit.msg());
            }
            // 计数器加1,并设置1秒过期
            stringRedisTemplate.opsForValue().increment(key);
            stringRedisTemplate.expire(key, 1, TimeUnit.SECONDS);
        }
        return joinPoint.proceed();
    }
}

第四步 使用注解

    @Limit(
            key = "getByOrderNo",
            permitsPerSecond = 1,
            msg = "当前访问较多,请稍后再试!"
    )
    @GetMapping("getByOrderNo")
    public RestResponse getByOrderNo(String orderNo) {
        Map<String, Object> info = checkService.info(orderNo);
        return RestResponse.success().put(info);
    }

测试

正常请求未触发限流

请添加图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

简单哟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值