一、说明
1.测试环境:springboot 2.0.9.RELEASE版本+jdk1.8+redis集群
2.安装redis的教程:REDIS学习总结(一)单机集群搭建
3.需要注意的是,在线程复用的情况下对redisson使用的影响:场景->一个人频繁刷接口,当这个人每次访问服务时,线程ID可能相同,redisson类似于可重入锁,最终会出现拦不住刷接口的行为。考虑到这点,我在切面中使用了以下逻辑,真正控制在锁自动释放前,用户刷接口频率。
boolean excute = !rateLimited || rLock.getHoldCount() == 1;
if (excute){
log.info("方法执行中:[{}]", key);
obj = joinPoint.proceed();
} else {
obj = redissonLock.msg();
}
4.使用例子:
@RedissonLock 锁整个方法
@RedissonLock(lockIndexs = 0, rateLimited = true) 锁第一个参数, 并限速
@RedissonLock(lockIndexs = {0,1}, rateLimited = true) 锁第一个参数和第二个参数组合, 并限速
@RedissonLock(lockIndexs = {1,2}) 锁第二个参数和第三个参数组合
@RedissonLock(lockIndexs = 0,fieldNames = "transId") 锁第一个参数属性等于transId
@RedissonLock(lockIndexs = {0,1},fieldNames = {"transId","id"}) 锁第一个参数属性等于transId和第二个参数属性等于id的组合
5.源码路径:https://github.com/Juwenzhe/redisson-annolock.git
注:在项目【Zjmzxfxhl】基础上改造升级完成,同时推荐关注该项目!
二、使用场景
/**
* 使用场景一:大并发访问减小接口压力
* 用户获得锁的条件是,上一个线程执行结束 或 锁自动释放时刻在其等待时间内
* 注意:没获取到锁的用户快速失败,体验可能不好
* @return 压测结果:并发5请求,只有一个获取到锁,其他请求发现锁被占用5秒后才释放,直接返回
*/
@RequestMapping(value = "/getToken1", method = RequestMethod.GET)
@RedissonLock(waitTime = 1, leaseTime = 5, msg = "活动太火爆")
public Object getToken1() {
try {
// 模拟方法执行10秒
Thread.sleep(10000);
} catch (InterruptedException e) {
log.info("线程sleep被打断..");
}
return "juwenzhe123321juwenzhe";
}
/**
* 使用场景二:将第一个参数对象的userId作为锁key,并限速,适用于接口防刷场景
* @return 压测结果:5秒100请求,每个不同的用户只有一个请求成功
*/
@RequestMapping(value = "/getToken2", method = RequestMethod.POST)
@RedissonLock(rateLimited = true, waitTime = 0, leaseTime = 5, lockIndexs = {0}, fieldNames = {"userId"} , msg = "获取token过于频繁")
public Object getToken2(@RequestBody User user) {
return "juwenzhe123321juwenzhe" + user.getUserId();
}
三、参考与推荐
1.分布式锁:https://zjm16.gitee.io/zjmzxfzhl-doc/zdyzj.html#redissonlock
2.Redisson实现分布式锁(1)---原理 https://www.cnblogs.com/qdhxhz/p/11046905.html