iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > Python >SpringBoot使用自定义注解+AOP+Redis实现接口限流的实例代码
  • 164
分享到

SpringBoot使用自定义注解+AOP+Redis实现接口限流的实例代码

2024-04-02 19:04:59 164人浏览 薄情痞子

Python 官方文档:入门教程 => 点击学习

摘要

目录为什么要限流限流背景实现限流1、引入依赖2、自定义限流注解3、限流切面4、写一个简单的接口进行测试5、全局异常拦截6、接口测试为什么要限流 系统在设计的时候,我们会有一个系统的预

为什么要限流

系统在设计的时候,我们会有一个系统的预估容量,长时间超过系统能承受的TPS/QPS阈值,系统有可能会被压垮,最终导致整个服务不可用。为了避免这种情况,我们就需要对接口请求进行限流。

所以,我们可以通过对并发访问请求进行限速或者一个时间窗口内的的请求数量进行限速来保护系统或避免不必要的资源浪费,一旦达到限制速率则可以拒绝服务、排队或等待。

限流背景

系统有一个获取手机短信验证码的接口,因为是开放接口,所以为了避免用户不断的发送请求获取验证码,防止恶意刷接口的情况发生,于是用最简单的计数器方式做了限流,限制每个IP每分钟只能请求一次,然后其他每个手机号的时间窗口限制则是通过业务逻辑进行判断。一般一些接口访问量比较大的,可能会压垮系统的,则需要加入流量限制!如:秒杀等...

实现限流

1、引入依赖

<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>       

2、自定义限流注解

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RateLimiter
{
    
     String key() default Constants.RATE_LIMIT_KEY;

    
     int time() default 60;

    
    int count() default 100;

    
    LimitType limitType() default LimitType.DEFAULT;

    
    String limitMsg() default "访问过于频繁,请稍候再试";
}

3、限流切面

@Aspect
@Component
public class RateLimiterAspect {

    private final static Logger log = LoggerFactory.getLogger(RateLimiterAspect.class);

    @Autowired
    private RedisUtils redisUtils;

    @Before("@annotation(rateLimiter)")
    public void doBefore(JoinPoint point, RateLimiter rateLimiter) throws Throwable
    {
        int time = rateLimiter.time();
        int count = rateLimiter.count();
        long total = 1L;

        String combineKey = getCombineKey(rateLimiter, point);
        try
        {
            if(redisUtils.hasKey(combineKey)){
                total = redisUtils.incr(combineKey,1);  //请求进来,对应的key加1
                if(total > count)
                    throw new ServiceRuntimeException(rateLimiter.limitMsg());
            }else{
                redisUtils.set(combineKey,1,time);  //初始化key
            }
        }
        catch (ServiceRuntimeException e)
        {
            throw e;
        }
        catch (Exception e)
        {
            throw new ServiceRuntimeException("网络繁忙,请稍候再试");
        }
    }

    
    public String getCombineKey(RateLimiter rateLimiter, JoinPoint point)
    {
        StringBuffer stringBuffer = new StringBuffer(rateLimiter.key());
        if (rateLimiter.limitType() == LimitType.IP)
        {
            stringBuffer.append(IpUtils.getIpAddr(ServletUtils.getRequest())).append("-");
        }
        MethodSignature signature = (MethodSignature) point.getSignature();
        Method method = signature.getMethod();
        Class<?> targetClass = method.getDeclarinGClass();
        stringBuffer.append(targetClass.getName()).append("-").append(method.getName());
        return stringBuffer.toString();
    }
}

4、写一个简单的接口进行测试

@RestController
public class TestController {

    @RateLimiter(time = 60, count = 1, limitType = LimitType.IP, limitMsg = "一分钟内只能请求一次,请稍后重试")
    @GetMapping("/hello")
    public ResultMsg hello() {
        return ResultMsg.success("Hello World!");
    }
}

5、全局异常拦截

@RestControllerAdvice
public class GlobalExceptionHandler {
    private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    
    @ExceptionHandler(ServiceRuntimeException.class)
    public ResultMsg handleServiceException(ServiceRuntimeException e, httpservletRequest request)
    {
        return ResultMsg.error(e.getMessage());
    }

    
    @ExceptionHandler(Exception.class)
    public ResultMsg handleException(Exception e, HttpServletRequest request)
    {
        return ResultMsg.error("系统异常");
    }
}

6、接口测试

1)第一次发送,正常返回结果

2)一分钟内第二次发送,返回错误,限流提示

好了,大功告成啦

还有其他的限流方式,如滑动窗口限流方式(比计数器更严谨)、令牌桶等...,有兴趣的小伙伴可以学习一下

源码

https://gitee.com/jae_1995/ratelimiter

到此这篇关于SpringBoot使用自定义注解+AOP+Redis实现接口限流的文章就介绍到这了,更多相关SpringBoot接口限流内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: SpringBoot使用自定义注解+AOP+Redis实现接口限流的实例代码

本文链接: https://www.lsjlt.com/news/167050.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作