springboot实现自定义注解限流

前言

最近看到有人在拾壹的文章下面刷了好多评论,小伙伴还是用心了,特意以此来提醒拾壹该加限流处理了。也是,如果网站不加限流处理,对于访问量多的网站来说,但凡有一部分人恶意刷接口,这个网站十有八九就崩了,加了限流的话在规定次数内他只能调用这么多次,后续的请求都不会放行,可以有效的抵制刷接口的人。当然,拾壹这种小网站还是不怕你们刷,毕竟崩了就崩了,无伤大雅,不过限流也还是要加的,下面就来一个简单的限流处理吧。

引入依赖
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

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

自定义注解的话就肯定需要使用到切面了,所以需要引入aop,然后又是通过redis来限流,所以还需要引入redis

创建AccessLimit注解文件
/**
 * @title: AccessLimit
 * @description: 限流注解
 */
@Documented
@Target(ElementType.METHOD)//注解放置的目标位置即方法级别
@Retention(RetentionPolicy.RUNTIME)//注解在哪个阶段执行
public @interface AccessLimit {

    /**
     * 在时间窗内的限流次数
     * @return
     */
    public int count() default 10;

    /**
     * 限流时间窗
     * @return
     */
    public int time() default 10;  

    public boolean pass() default false;  // 超过限流次数是否也放行

}
创建Aop切面类
/**
 * @title: AccessLimitAspect
 * @description: 限流切面类
 */
@Aspect
@Component
@RequiredArgsConstructor
public class AccessLimitAspect {

    private static final Logger logger = LoggerFactory.getLogger(AccessLimitAspect.class);

    private final RedisTemplate redisTemplate;

    @Before("@annotation(accessLimit)")
    public void doBefore(JoinPoint joinPoint, AccessLimit accessLimit) throws Throwable {
        int time = accessLimit.time();

        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
            // 拼接redis key = IP + Api限流
            String key = IpUtil.getIp(request) + request.getRequestURI();
            // 获取redis的value
            Integer maxTimes = null;
            Object value = redisTemplate.opsForValue().get(key);
            if (value != null) {
                maxTimes = (Integer) value;
            }
            if (maxTimes == null) {
                // 如果redis中没有该ip对应的时间则表示第一次调用,保存key到redis
                redisTemplate.opsForValue().set(key, 1, time, TimeUnit.SECONDS);
            } else if (maxTimes < accessLimit.count()) {
                // 如果redis中的时间比注解上的时间小则表示可以允许访问,这是修改redis的value时间
                redisTemplate.opsForValue().set(key, maxTimes + 1, time, TimeUnit.SECONDS);
            } else {
                // 请求过于频繁
                logger.info("API请求限流拦截启动,{} 请求过于频繁", key);
                throw new BusinessException("请求过于频繁,稍后重试");
            }
    }
}
使用注解
    @AccessLimit
    @GetMapping(value = "collect")
    public ResponseResult collect(Integer articleId, HttpServletRequest request) {
        return apiCollectService.collect(articleId,request);
    }

在需要进行限流的方法上加上AcessLimit注解,当然后面也是可以配置参数的,我这里是用的默认,所以没有加,如果需要配置的话可以参考下面这个

    @AccessLimit(count = 15,time = 20)

至此,方法限流也就完成了,只需简简单单的几步就可以完成对方法的限流,是不是很so easy~~呢

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值