quan-limiter
大约 5 分钟自定义工具配置分布式锁限流
quan-limiter
是一个基于 Spring AOP
框架实现的限制器组件。其内部默认提供了基于 Redisson 实现的限制器执行器。 可用于分布式流量限制等场景。
通过自定义实现限制器的执行器,可改变默认的执行器实现,达到高度定制化的目的。
使用方法
引入工具依赖包。
gradle
dependencies {
api project(':quan-tools:quan-limiter')
}
yml配置:
提示
若不配置限制器属性,则应用系统默认的属性配置
quan:
tools:
limiter:
# 令牌租赁时间(令牌有效期,当程序执行完成或令牌到期时,清除令牌)默认:1000(单位:毫秒)
lease-time: 1000
# 获取令牌最大等待时间 默认:1000(单位:毫秒)
wait-time: 1000
# 令牌的前缀(构建令牌的默认前缀)默认:quan:limiter
token-prefix: quan:limiter
# 限制器执行器 默认:RedissonLimiterExecutor 执行器(基于Redisson实现)
executor: cn.javaquan.tools.limiter.executor.redisson.RedissonLimiterExecutor
# 是否开启限制器 默认:true,当配置为false时,限制器将不生效
enabled: false
# 基于 Redisson 实现的限制器执行器
redisson:
# 默认启用 Redisson 实现的限制器执行器
enabled: true
限制器属性配置说明
enabled
- 类型:
boolean
- 默认: false
是否开启限制器,当配置为false时,限制器将不生效。
tokenPrefix
- 类型:
string
- 默认: quan:limiter
令牌的前缀。
leaseTime
- 类型:
long
- 默认: 1000
- 单位: 毫秒
持有令牌的有效期,当以申请的令牌超过有效期时,令牌自动失效。
waitTime
- 类型:
long
- 默认: 1000
- 单位: 毫秒
获取令牌的最大等待时间,当申请获取令牌超过最大等待时间时,令牌获取失败。
executor
- 类型:
Class<? extends LimiterExecutor>
- 默认:cn.javaquan.tools.limiter.executor.redisson.RedissonLimiterExecutor
自定义限制器执行器,可改变默认的执行器的实现,达到高度定制化的目的。
redisson
基于 Redisson 实现的限制器执行器配置
redisson.enabled
- 类型:
boolean
- 默认: true
是否启用 Redisson 实现的限制器执行器,当配置为false时,执行器将不生效。
限制器使用示例
/**
* @author JavaQuan
* @date 2021/6/19 11:27
*/
@RestController("/test/")
public class Test {
// 默认获取全路径构建token,令牌过期时间为1秒,获取令牌最大等待时间为1秒
@Limiter
@PostMapping("add")
public void add(User user) {
}
// 如果配置了参数,则按照顺序加入到token后末尾
// 令牌参数示例:cn.javaquan.app#add_userId_phone
// 令牌示例:quan:limiter:令牌参数的MD5值
@Limiter(params = {"#user.userId", "#user.phone"})
@PostMapping("add")
public void add(User user) {
}
/**
* 配置 nullable 属性,要求 params 是否可以为空。默认: true
* true: 令牌参数可以为空,即任何情况下,均会创建令牌。
* false: 令牌参数不可以为空,要求令牌参数必须存在。如果令牌参数不存在,则不会创建令牌;意味着限制器将不生效。
*/
@Limiter(params = {"#user.userId"}, nullable = false)
@PostMapping("add")
public void add(User user) {
}
/**
* 程序执行完成后,是否自动释放令牌。默认: true
*
* 自动释放的场景:
* 1. 当程序执行完成后,自动释放。
* 2. 当令牌有效期超过 leaseTime 配置后,自动释放。
*
* 当配置值为 false 时,必须等待令牌有效期超过 leaseTime 配置后释放。
*
* 示例:
* API执行完成后,必须等待 60 秒才能再次请求。
*
* 典型的应用场景:用户根据手机号码获取短信,必须等待一定的时间后才能再次获取短信。
*/
@Limiter(params = {"#user.userId"}, leaseTime = 60000, automaticReleaseLock = false)
@PostMapping("add")
public void add(User user) {
}
/**
* 如果配置了参数,则按照顺序加入到token后末尾
* 如果配置了数组参数,则将数组
* 令牌参数示例:
* cn.javaquan.app#add_userId_phone:userId1
* cn.javaquan.app#add_userId_phone:userId2
*
* 令牌示例:
* quan:limiter:令牌参数userId1的MD5值
* quan:limiter:令牌参数userId2的MD5值
*/
@Limiter(params = {"#user.userId", "#user.phone"}, arrayParams = {"#user.userIds"})
@PostMapping("add")
public void add(User user) {
}
// 手动配置令牌有效期为2000(单位:毫秒),获取令牌等待时间为1000(单位:毫秒)
// 获取令牌等待时间建议根据程序执行效率评估。避免等待时间过长
@Limiter(params = {"#user.userId", "#user.phone"}, leaseTime = 2000, waitTime = 1000)
@PostMapping("add")
public void add(User user) {
}
// 配置令牌桶限流 /// 由于阿里云集群版限制,新版将不启用,后期视情况扩展其它模式实现
@Limiter(
// 配置令牌参数
params = {"#user.userId", "#user.phone"},
rateParams = {
// 10秒内,最多请求1次
@RateParam(rate = 1, rateInterval = 10),
// 30秒内,最多请求2次(若exclude排除属性,当获取的参数值不为空时,排除当前规则,即则规则无效)
@RateParam(rate = 2, rateInterval = 30, exclude = "#user.memberActivity")
},
// 关闭默认限流,默认为开启
enableDefault = false
)
@PostMapping("add")
public void add(User user) {
}
}
扩展支持
自定义实现限制器执行器
/**
* 自定义限制器执行器
* @author JavaQuan
* @date 2021/6/19 11:55
*/
public class CustomExecutor extends AbstractLimiterExecutor<Object> {
/**
* 根据令牌执行限制器,申请执行权限
*
* @param token 令牌
* @param waitTime 获取令牌的最大时间,超时将获取失败,单位:毫秒
* @param leaseTime 持有令牌的时间,单位:毫秒
* @return 限制器执行返回的后置处理器
*/
@Override
public LimiterPostProcessor<Object> execute(String token, long waitTime, long leaseTime) throws Exception {
/// TODO 执行自定义的流程
/// TODO 获取自定义实现限制器执行返回的实例
final Object instance = Object.newInstance();
final boolean locked = instance.execute(waitTime, leaseTime);
return getPostProcessor(locked, lockInstance);
}
/**
* 释放限制器
*
* @param instance {@link LimiterPostProcessor#getInstance()}
* @return 是否释放成功
*/
@Override
public boolean release(Object instance) {
/// TODO 根据自定义实现限制器执行返回的实例,释放限制器
return false;
}
}
使用自定义限流执行器
/**
* @author wangquan
* @date 2021/6/19 11:27
*/
@RestController("/test/")
public class Test {
// 使用自定义限流执行器
@Limiter(executor = CustomExecutor.class)
@PostMapping("delete")
public void delete(User user) {
}
}
常用SPEL 表达式语法
提示
更多高级用法,请参考 Spring SPEL
字面常量:
#参数名称.属性名称
例:#user.userId
集合投影:
#参数名称.集合属性.![#this.对象属性]
例:#role.perms.![#this.permId]