一 、引入jar包
<!-- springboot 对redis的支持-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<!-- springboot 对aop的支持 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- redisson -->
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.9.1</version>
</dependency>
二、配置文件
#redis配置
spring.redis.host=39.100.91.122
spring.redis.port=6379
spring.redis.database=0
spring.redis.timeout=5000ms
#redisson客户端连接超时时间(ms)
redisson.timeout=10000
三、Redisson代码
3.1 分布式锁接口
/**
* 分布式锁接口
*/
public interface DistributeLocker {
/**
* 加锁
* @param lockKey key
*/
void lock(String lockKey);
/**
* 释放锁
*
* @param lockKey key
*/
void unlock(String lockKey);
/**
* 加锁锁,设置有效期
*
* @param lockKey key
* @param timeout 有效时间,默认时间单位在实现类传入
*/
void lock(String lockKey, int timeout);
/**
* 加锁,设置有效期并指定时间单位
* @param lockKey key
* @param timeout 有效时间
* @param unit 时间单位
*/
void lock(String lockKey, int timeout, TimeUnit unit);
/**
* 尝试获取锁,获取到则持有该锁返回true,未获取到立即返回false
* @param lockKey
* @return true-获取锁成功 false-获取锁失败
*/
boolean tryLock(String lockKey);
/**
* 尝试获取锁,获取到则持有该锁leaseTime时间.
* 若未获取到,在waitTime时间内一直尝试获取,超过watiTime还未获取到则返回false
* @param lockKey key
* @param waitTime 尝试获取时间
* @param leaseTime 锁持有时间
* @param unit 时间单位
* @return true-获取锁成功 false-获取锁失败
*/
boolean tryLock(String lockKey, long waitTime, long leaseTime, TimeUnit unit)
throws InterruptedException;
/**
* 锁是否被任意一个线程锁持有
* @param lockKey
* @return true-被锁 false-未被锁
*/
boolean isLocked(String lockKey);
}
3.2 redisson实现分布式锁
/**
* redisson实现分布式锁接口
*/
public class RedissonDistributeLocker implements DistributeLocker {
private RedissonClient redissonClient;
public RedissonDistributeLocker(RedissonClient redissonClient) {
this.redissonClient = redissonClient;
}
@Override
public void lock(String lockKey) {
RLock lock = redissonClient.getLock(lockKey);
lock.lock();
}
@Override
public void unlock(String lockKey) {
RLock lock = redissonClient.getLock(lockKey);
lock.unlock();
}
@Override
public void lock(String lockKey, int leaseTime) {
RLock lock = redissonClient.getLock(lockKey);
lock.lock(leaseTime, TimeUnit.MILLISECONDS);
}
@Override
public void lock(String lockKey, int timeout, TimeUnit unit) {
RLock lock = redissonClient.getLock(lockKey);
lock.lock(timeout, unit);
}
@Override
public boolean tryLock(String lockKey) {
RLock lock = redissonClient.getLock(lockKey);
return lock.tryLock();
}
@Override
public boolean tryLock(String lockKey, long waitTime, long leaseTime,
TimeUnit unit) throws InterruptedException {
RLock lock = redissonClient.getLock(lockKey);
return lock.tryLock(waitTime, leaseTime, unit);
}
@Override
public boolean isLocked(String lockKey) {
RLock lock = redissonClient.getLock(lockKey);
return lock.isLocked();
}
}
3.3 redisson锁的工具类
/**
* redisson锁工具类
*/
public class RedissonLockUtils {
private static DistributeLocker locker;
public static void setLocker(DistributeLocker locker) {
RedissonLockUtils.locker = locker;
}
public static void lock(String lockKey) {
locker.lock(lockKey);
}
public static void unlock(String lockKey) {
locker.unlock(lockKey);
}
public static void lock(String lockKey, int timeout) {
locker.lock(lockKey, timeout);
}
public static void lock(String lockKey, int timeout, TimeUnit unit) {
locker.lock(lockKey, timeout, unit);
}
public static boolean tryLock(String lockKey) {
return locker.tryLock(lockKey);
}
public static boolean tryLock(String lockKey, long waitTime, long leaseTime,
TimeUnit unit) throws InterruptedException {
return locker.tryLock(lockKey, waitTime, leaseTime, unit);
}
public static boolean isLocked(String lockKey) {
return locker.isLocked(lockKey);
}
}
3.4 初始化Redisson
/**
* redisson bean管理
*/
@Configuration
public class RedissonConfig {
@Autowired
private Environment env;
/**
* Redisson客户端注册
* 单机模式
*/
@Bean(destroyMethod = "shutdown")
public RedissonClient createRedissonClient() {
Config config = new Config();
SingleServerConfig singleServerConfig = config.useSingleServer();
singleServerConfig.setAddress("redis://" + env.getProperty("spring.redis.host") + ":" + env.getProperty("spring.redis.port"));
singleServerConfig.setTimeout(Integer.valueOf(env.getProperty("redisson.timeout")));
return Redisson.create(config);
}
/**
* 分布式锁实例化并交给工具类
* @param redissonClient
*/
@Bean
public RedissonDistributeLocker redissonLocker(RedissonClient redissonClient) {
RedissonDistributeLocker locker = new RedissonDistributeLocker(redissonClient);
RedissonLockUtils.setLocker(locker);
return locker;
}
}
至此,便可以通过RedissonLockUtils来实现分布式锁。
四、AOP代码
4.1 分布式锁注解
/**
* 分布式锁注解
* 添加到方法 ,修饰以@RequestBody JSON对象接收参数的方法
*/
@Target(ElementType.METHOD) //注解在方法
@Retention(RetentionPolicy.RUNTIME)
public @interface RedissonLockAnnotation {
/**
* 指定组成分布式锁的key,以逗号分隔。
* 如:keyParts="name,age",则分布式锁的key为这两个字段value的拼接
* key=params.getString("name")+params.getString("age")
*/
String keyParts();
}
4.2 aop实现
/**
* 分布式锁/防重复提交 aop
*/
@Aspect
@Component
@Slf4j
public class RedissonLockAop {
/**
* 切点,拦截被 @RedissonLockAnnotation 修饰的方法
*/
@Pointcut("@annotation(com.icbc.cxlab.rtc.annotation.RedissonLockAnnotation)")
public void redissonLockPoint() {
}
@Around("redissonLockPoint()")
@ResponseBody
public APIResult checkLock(ProceedingJoinPoint pjp) throws Throwable {
//当前线程名
String threadName = Thread.currentThread().getName();
log.info("线程{}------进入分布式锁aop------", threadName);
//获取参数列表
Object[] objs = pjp.getArgs();
//因为只有一个JSON参数,直接取第一个
JSONObject param = (JSONObject) objs[0];
//获取该注解的实例对象
RedissonLockAnnotation annotation = ((MethodSignature) pjp.getSignature()).
getMethod().getAnnotation(RedissonLockAnnotation.class);
//生成分布式锁key的键名,以逗号分隔
String keyParts = annotation.keyParts();
StringBuffer keyBuffer = new StringBuffer();
if (StringUtils.isEmpty(keyParts)) {
log.info("线程{} keyParts设置为空,不加锁", threadName);
return (APIResult) pjp.proceed();
} else {
//生成分布式锁key
String[] keyPartArray = keyParts.split(",");
for (String keyPart : keyPartArray) {
keyBuffer.append(param.getString(keyPart));
}
String key = keyBuffer.toString();
log.info("线程{} 要加锁的key={}", threadName, key);
//获取锁
if (RedissonLockUtils.tryLock(key, 3000, 5000, TimeUnit.MILLISECONDS)) {
try {
log.info("线程{} 获取锁成功", threadName);
return (APIResult) pjp.proceed();
} finally {
RedissonLockUtils.unlock(key);
log.info("线程{} 释放锁", threadName);
}
} else {
log.info("线程{} 获取锁失败", threadName);
return new APIResult(-9, "请求超时");
}
}
}
}
五、分布式锁应用
@PostMapping(value = "testLock", consumes = "application/json")
@RedissonLockAnnotation(keyParts = "name,age")
public APIResult testLock(@RequestBody JSONObject params) {
/**
* 分布式锁key=params.getString("name")+params.getString("age");
* 此时name和age均相同的请求不会出现并发问题
*/
//TODO 业务处理
return new APIResult(0, "SUCCESS");
}