From 033b7f5c3c89841e3a29d9ff3c99224d0f695e24 Mon Sep 17 00:00:00 2001 From: rstyro Date: 2026年1月22日 15:21:30 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0redisson=E7=9A=84=E9=99=90?= =?UTF-8?q?=E6=B5=81=E7=A4=BA=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- SpringBoot-limit/pom.xml | 8 +++ .../limit/annotation/RedissonRateLimit.java | 32 ++++++++++ .../limit/aspect/RedissonRateLimitAspect.java | 63 +++++++++++++++++++ .../lrshuai/limit/config/RedissonConfig.java | 46 ++++++++++++++ .../controller/RedissonRateController.java | 19 ++++++ 5 files changed, 168 insertions(+) create mode 100644 SpringBoot-limit/src/main/java/top/lrshuai/limit/annotation/RedissonRateLimit.java create mode 100644 SpringBoot-limit/src/main/java/top/lrshuai/limit/aspect/RedissonRateLimitAspect.java create mode 100644 SpringBoot-limit/src/main/java/top/lrshuai/limit/config/RedissonConfig.java create mode 100644 SpringBoot-limit/src/main/java/top/lrshuai/limit/controller/RedissonRateController.java diff --git a/SpringBoot-limit/pom.xml b/SpringBoot-limit/pom.xml index 253c459..3ce52f5 100644 --- a/SpringBoot-limit/pom.xml +++ b/SpringBoot-limit/pom.xml @@ -16,6 +16,7 @@ 1.8 + 3.22.0 @@ -50,6 +51,13 @@ spring-boot-starter-test test + + + org.redisson + redisson + ${redisson.version} + + diff --git a/SpringBoot-limit/src/main/java/top/lrshuai/limit/annotation/RedissonRateLimit.java b/SpringBoot-limit/src/main/java/top/lrshuai/limit/annotation/RedissonRateLimit.java new file mode 100644 index 0000000..493581b --- /dev/null +++ b/SpringBoot-limit/src/main/java/top/lrshuai/limit/annotation/RedissonRateLimit.java @@ -0,0 +1,32 @@ +package top.lrshuai.limit.annotation; + +import java.lang.annotation.*; + +/** + * redisson限流注解 + */ +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface RedissonRateLimit { + + /** + * 限流key,支持SpEL表达式 + */ + String key() default ""; + + /** + * 令牌生成速率 (每秒生成的令牌数) + */ + long rate() default 10; + + /** + * 每次请求消耗的令牌数 + */ + int tokens() default 1; + + /** + * 限流时的提示信息 + */ + String message() default "请求过于频繁,请稍后再试"; +} diff --git a/SpringBoot-limit/src/main/java/top/lrshuai/limit/aspect/RedissonRateLimitAspect.java b/SpringBoot-limit/src/main/java/top/lrshuai/limit/aspect/RedissonRateLimitAspect.java new file mode 100644 index 0000000..e037045 --- /dev/null +++ b/SpringBoot-limit/src/main/java/top/lrshuai/limit/aspect/RedissonRateLimitAspect.java @@ -0,0 +1,63 @@ +package top.lrshuai.limit.aspect; + +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.redisson.api.RRateLimiter; +import org.redisson.api.RateIntervalUnit; +import org.redisson.api.RateType; +import org.redisson.api.RedissonClient; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import top.lrshuai.limit.annotation.RedissonRateLimit; +import top.lrshuai.limit.common.R; +import top.lrshuai.limit.util.AopUtil; + +import java.lang.reflect.Method; + +@Aspect +@Component +@Slf4j +public class RedissonRateLimitAspect { + + @Autowired + private RedissonClient redissonClient; + + /** + * 切片-方法级别 + */ + @Around("@annotation(rateLimit)") + public Object around(ProceedingJoinPoint joinPoint, RedissonRateLimit rateLimit) throws Throwable { + String key = buildRateLimitKey(joinPoint, rateLimit); + RRateLimiter rRateLimiter = redissonClient.getRateLimiter(key); + // 初始化限流器 + rRateLimiter.trySetRate(RateType.OVERALL, rateLimit.rate(), 1, RateIntervalUnit.SECONDS); + if (!rRateLimiter.tryAcquire(rateLimit.tokens())) { + log.warn("接口限流触发 - key: {}, 方法: {}", key, joinPoint.getSignature().getName()); + return R.fail(rateLimit.message()); + } + return joinPoint.proceed(); + } + + /** + * 构建限流key + */ + private String buildRateLimitKey(ProceedingJoinPoint joinPoint, RedissonRateLimit rateLimit) { + String key = rateLimit.key(); + // 如果key为空,使用默认格式 + if (key.isEmpty()) { + MethodSignature signature = (MethodSignature) joinPoint.getSignature(); + Method method = signature.getMethod(); + String className = method.getDeclaringClass().getSimpleName(); + String methodName = method.getName(); + return String.format("rate_limit:%s:%s", className, methodName); + } + // 如果key包含SpEL表达式,进行解析 + if (key.contains("#")) { + return AopUtil.parseSpel(key, joinPoint); + } + return key; + } +} diff --git a/SpringBoot-limit/src/main/java/top/lrshuai/limit/config/RedissonConfig.java b/SpringBoot-limit/src/main/java/top/lrshuai/limit/config/RedissonConfig.java new file mode 100644 index 0000000..1c8c1ea --- /dev/null +++ b/SpringBoot-limit/src/main/java/top/lrshuai/limit/config/RedissonConfig.java @@ -0,0 +1,46 @@ +package top.lrshuai.limit.config; + + +import org.redisson.Redisson; +import org.redisson.api.RedissonClient; +import org.redisson.config.Config; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.util.StringUtils; + +/** + * redisson 配置,下面是单节点配置: + * 官方wiki地址:https://github.com/redisson/redisson/wiki/2.-%E9%85%8D%E7%BD%AE%E6%96%B9%E6%B3%95#26-%E5%8D%95redis%E8%8A%82%E7%82%B9%E6%A8%A1%E5%BC%8F + * + */ +@Configuration +public class RedissonConfig { + + @Value("${spring.redis.host}") + private String host; + + @Value("${spring.redis.port}") + private String port; + + @Value("${spring.redis.password}") + private String password; + + @Bean + public RedissonClient redissonClient(){ + Config config = new Config(); + //单节点 + config.useSingleServer().setAddress("redis://" + host + ":" + port); + if(StringUtils.isEmpty(password)){ + config.useSingleServer().setPassword(null); + }else{ + config.useSingleServer().setPassword(password); + } + //添加主从配置 +// config.useMasterSlaveServers().setMasterAddress("").setPassword("").addSlaveAddress(new String[]{"",""}); + + // 集群模式配置 setScanInterval()扫描间隔时间,单位是毫秒, //可以用"rediss://"来启用SSL连接 +// config.useClusterServers().setScanInterval(2000).addNodeAddress("redis://127.0.0.1:7000", "redis://127.0.0.1:7001").addNodeAddress("redis://127.0.0.1:7002"); + return Redisson.create(config); + } +} diff --git a/SpringBoot-limit/src/main/java/top/lrshuai/limit/controller/RedissonRateController.java b/SpringBoot-limit/src/main/java/top/lrshuai/limit/controller/RedissonRateController.java new file mode 100644 index 0000000..e96a54a --- /dev/null +++ b/SpringBoot-limit/src/main/java/top/lrshuai/limit/controller/RedissonRateController.java @@ -0,0 +1,19 @@ +package top.lrshuai.limit.controller; + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; +import top.lrshuai.limit.annotation.RedissonRateLimit; +import top.lrshuai.limit.common.R; + +@RestController +@RequestMapping("/redissonRate") +public class RedissonRateController { + + @GetMapping("/queryQuotaInfo") + @RedissonRateLimit(key = "'queryQuotaInfo:' + #storageType",rate = 1) + public R queryQuotaInfo(@RequestParam(value = "storageType") String storageType) { + return R.ok("storageType:"+storageType); + } +}

AltStyle によって変換されたページ (->オリジナル) /