当前位置: 首页 > news >正文

SpringBoot实现一个Redis限流注解

springBoot实现的一个限流注解

文章目录

目录

文章目录

一、使用步骤

1.引入库

2.代码实现

1.添加注解

2.新增限流AOP实现

 3.实现代码的拦截

 4.最终结果

总结

一、使用步骤

1.引入库

代码如下(示例):

        <!-- 引入SpringBoot Aop依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>

2.代码实现

1.添加注解

package com.hhh.springai_test.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RedisLimiting {

    int number() default 3;

    int time() default 60;

    String message() default "请求过于频繁,请稍后再试";


}

2.新增限流AOP实现

package com.hhh.springai_test.aop;

import cn.hutool.crypto.digest.MD5;
import com.hhh.springai_test.annotation.RedisLimiting;
import com.hhh.springai_test.common.ErrorCode;
import com.hhh.springai_test.exception.BusinessException;
import com.hhh.springai_test.utils.RedisUtils;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.lang.reflect.Parameter;

@Aspect
@Component("redisLimitingAspect")
@Slf4j
public class RedisLimitingAspect {

    @Autowired
    private RedisUtils redisUtils;

    @Around("@annotation(com.hhh.springai_test.annotation.RedisLimiting)")  // 只拦截带 @redisLimiting 的方法
    public Object redisLimiting(ProceedingJoinPoint joinPoint) throws Throwable {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod(); // 直接获取被代理的方法
        // 获取 @redisLimiting 注解
        RedisLimiting annotation = method.getAnnotation(RedisLimiting.class);
        if (annotation == null) {
            return joinPoint.proceed(); // 没有注解,直接执行方法
        }
        int limit = annotation.number(); // 限制次数
        int expire = annotation.time();  // 过期时间
        String message = annotation.message();

        log.info("拦截方法: {}, 限流 key: {}, 限流次数: {}, 过期时间: {} 秒",
                method.getName(), limit, expire);

        // 执行限流逻辑
        boolean isAllowed = checkRedisLimiting(method, joinPoint.getArgs(), limit, expire);
        if (!isAllowed) {
            throw new BusinessException(ErrorCode.BUSY_ERROR,message);
        }

        return joinPoint.proceed(); // 执行原方法
    }

    private boolean checkRedisLimiting(Method method, Object[] args, int limit, int expire) {
        // 生成 Redis Key
        String redisKey = generateRedisKey(method, args);
        // 查询 Redis 是否存在
        Object o = redisUtils.get(redisKey);
        if (o == null) {
            redisUtils.setex(redisKey, 1, expire); // 初始值设为1,并设置过期时间
            return true;
        } else {
            int count = Integer.parseInt(o.toString());
            if (count >= limit) {
                return false; // 超过限制
            } else {
                redisUtils.increment(redisKey, 1); // 递增计数
                return true;
            }
        }
    }

    private String generateRedisKey(Method method, Object[] args) {
        StringBuilder builder = new StringBuilder();
        builder.append(method.getDeclaringClass().getName()).append(":").append(method.getName()).append(":");
        Parameter[] parameters = method.getParameters();
        for (int i = 0; i < parameters.length; i++) {
            builder.append(parameters[i].getName()).append("=").append(args[i]).append("&");
        }
        return MD5.create().digestHex16(builder.toString()); // 生成唯一 Redis Key
    }
}

 3.实现代码的拦截

@GetMapping("/getAllModel")
    @RedisLimiting(number = 3, time = 60,message = "不要再请求我的获取aiModel方法了")
    public BaseResponse<List<AiModelVO>> getAllModel() {
        return ResultUtils.success(aiModelService.getAllModel());
    }

 4.最终结果


总结

提示:这里对文章进行总结:
例如:以上就是今天要讲的内容,本文仅仅简单介绍了pandas的使用,而pandas提供了大量能使我们快速便捷地处理数据的函数和方法。

相关文章:

  • 如何从受 Cloudflare 保护的网站提取数据:技术与挑战
  • 每日一题---数组中两个字符串的最小距离
  • 混淆矩阵概念
  • 使用kubeadm方式以及使用第三方工具sealos搭建K8S集群
  • 使用Node的http模块创建web服务,给客户端返回html页面时,css失效的根本原因(有助于理解http)
  • 走路碎步营养补充贴士
  • 使用libwebsocket写一个server
  • 【AI】利用Azure AI的元数据过滤器提升 RAG 性能并增强向量搜索案例
  • 【备考记录】三种校验码
  • pop是什么的缩写?为什么Python用它表示删除元素?
  • 【统计学相关笔记】2. 多元正态的Cochran定理
  • iptables练习笔记20250315
  • 盖革管死区时间导致脉冲丢失分析
  • 3.9/Q2,Charls最新文章解读!
  • 苹果电脑杀毒软件CleanMyMac
  • Android 手机启动过程
  • [C++Qt] 槽函数收不到信号问题(信号的注册)
  • 当大模型训练遇上“双向飙车”:DeepSeek开源周 DualPipe解析指南
  • 数字化转型 - 数据驱动
  • 【干货】Docker 在自动化测试和性能测试中的应用
  • 取得金奖西瓜品种独家使用权的上海金山,为何要到异地“试种”?
  • 纽约市长称墨西哥海军帆船撞桥事故已致2人死亡
  • 广东一驴友在英德野景点溺亡,家属被爆向21名同伴索赔86万
  • 专利申请全球领先!去年我国卫星导航与位置服务产值超5700亿元
  • 林诗栋/蒯曼混双取胜,国乒赢得多哈世乒赛开门红
  • 受贿3501万余元,中石油原董事长王宜林一审被判13年