分布式锁(限流)
# 介绍
主要功能 api 限流,短信,邮件 发送限流、控制恶意利用验证码功能 等。
# 安装依賴
- Apache Maven
<dependency>
<groupId>com.aizuda</groupId>
<artifactId>aizuda-limiter</artifactId>
<version>1.0.0</version>
</dependency>
- Gradle DSL
implementation("com.aizuda:aizuda-limiter:1.0.0")
测试案例 aizuda-limiter-example (opens new window)
注意
- 该组件居于 Redis 分布式缓存实现。
- 表单重复提交也可以使用该组件,利用限流来解决。
# 限流
@RestController
public class TestController {
/**
* 限流
* <p>
* 测试多次访问观察浏览器及控制台输出日志
* <p>
* http://localhost:8080/test?name=abc
*/
@GetMapping("/test")
@RateLimit(
// 唯一标示,支持SpEL表达式(可无),#name 为获取当前访问参数 name 内容
key = "#name",
// 限定阈值,时间间隔 interval 范围内超过该数量会触发锁
count = 2,
// 限制间隔时长(可无,默认 3 分钟)例如 5s 五秒,6m 六分钟,7h 七小时,8d 八天
interval = "100s",
// 策略(可无) ip 为获取当前访问IP地址(内置策略),自定义策略 user 为获取当前用户
strategy = {IpKeyGenerateStrategy.TYPE, UserRateLimitStrategy.TYPE},
// 提示消息(可无)
message = "请勿频繁操作"
)
public String test(String name) {
return "test" + name;
}
}
# 分布式锁
public class LockTestController {
private final LockTestComponent lockTestComponent;
private final ApplicationContext applicationContext;
private boolean alreadyReentrant;
/**
* 测试分布式锁的接口,建议多开几个实例测试、
* 支持可重如
* --server.port=8081
*
* @param name 参数
* @return map
*/
@GetMapping("/lock-reentrant")
@DistributedLock(
// 唯一标示,支持SpEL表达式(可无),'#name!=null?#name:'default'' 为获取当前访问参数 name 内容,如果为空,则默认为 'default'
key = "#name!=null?#name:'default'",
// 指定时间获取锁,如果在指定时间获取不到,则抛出对应异常,捕获此异常即可
tryAcquireTimeout = "5s",
acquireTimeoutMessage = "您请求的太快了"
)
public Map<String, Object> testLock(String name) {
log.debug("Thread:{} execute first method", Thread.currentThread().getId());
// 测试可重入
LockTestController bean = applicationContext.getBean(LockTestController.class);
if (!alreadyReentrant) {
alreadyReentrant = true;
bean.testLock(null);
log.info("运行到这里,说明此锁是可重入的");
}
try {
TimeUnit.SECONDS.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
Thread.currentThread().interrupt();
}
return new HashMap<String, Object>(4) {{
put("name", Optional.ofNullable(name).orElse("default string"));
}};
}
/**
* 测试获取分布式锁超时策略
*
* @param name 参数
* @return map
*/
@GetMapping("/failed-handler-test")
@DistributedLock(
// 唯一标示,支持SpEL表达式(可无),'#name!=null?#name:'default'' 为获取当前访问参数 name 内容,如果为空,则默认为 'default'
key = "#name!=null?#name:'default'",
// 指定时间获取锁,如果在指定时间获取不到,则抛出对应异常,捕获此异常即可
tryAcquireTimeout = "5s"
)
public Map<String, Object> testFailedHandler(String name) {
try {
TimeUnit.SECONDS.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
Thread.currentThread().interrupt();
}
return new HashMap<String, Object>(4) {{
put("name", Optional.ofNullable(name).orElse("default string"));
}};
}
/**
* 测试监听器
*
* @param name 参数
* @return map
*/
@GetMapping("/lock-listener-test")
@DistributedLock(
// 唯一标示,支持SpEL表达式(可无),'#name!=null?#name:'default'' 为获取当前访问参数 name 内容,如果为空,则默认为 'default'
key = "#name!=null?#name:'default'",
// 指定时间获取锁,如果在指定时间获取不到,则抛出对应异常,捕获此异常即可
tryAcquireTimeout = "5s"
)
public Map<String, Object> testLockListener(String name) {
lockTestComponent.testLockListener(name);
return new HashMap<String, Object>(4) {{
put("name", Optional.ofNullable(name).orElse("default string"));
}};
}
}
# 注解说明
- 速率限制注解 RateLimit
名称 | 说明 |
---|---|
key | 唯一标示,支持SpEL表达式 |
count | 限定阈值,时间间隔 interval 范围内超过该数量会触发锁 |
interval | 时间间隔,默认 3 分钟,例如 5s 五秒,6m 六分钟,7h 七小时,8d 八天 |
strategy | 限制策略 |
message | 提示消息,非必须 |
- 分布式锁限制注解 DistributedLock
名称 | 说明 |
---|---|
key | 唯一标示,支持SpEL表达式 |
tryAcquireTimeout | 获取分布式锁超时失败时间,默认 10 秒,例如 5s 五秒,6m 六分钟,7h 七小时,8d 八天 |
strategy | 加key策略,需要实现 IKeyGenerateStrategy 接口注入到spring中 |
acquireTimeoutMessage | 获取分布式锁超时提示 |
useDefaultStrategy | 是否使用默认的key生成策略 DefaultKeyGenerateStrategy 作为前缀 |
上次更新: 2022/03/29, 23:07:27