This commit is contained in:
clay
2024-03-06 17:44:09 +08:00
commit adaec0eadd
1493 changed files with 219939 additions and 0 deletions

View File

@@ -0,0 +1,54 @@
package cn.fateverse.common.lock;
import cn.fateverse.common.lock.aspect.ResubmitLockAspect;
import cn.fateverse.common.lock.service.DistributedLockService;
import cn.fateverse.common.lock.service.LockKeyGenerator;
import cn.fateverse.common.lock.service.impl.AbstractDistributeLockSupport;
import cn.fateverse.common.lock.service.impl.DistributedLockKeyGenerator;
import cn.fateverse.common.lock.service.impl.DistributedLockServiceImpl;
import cn.fateverse.common.lock.aspect.DistributedLockAspect;
import cn.fateverse.common.redis.aspect.RedisCacheAspect;
import cn.fateverse.common.lock.service.impl.RedisDistributeLockSupport;
import cn.fateverse.common.redis.configure.RedisConfig;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.context.annotation.Bean;
/**
* @author Clay
* @date 2023-05-21
*/
@ConditionalOnClass(RedisConfig.class)
public class RedisAutoConfiguration {
@Bean
public DistributedLockAspect distributedLockAspect(RedissonClient redissonClient, LockKeyGenerator lockKeyGenerator){
return new DistributedLockAspect(redissonClient, lockKeyGenerator);
}
@Bean
public ResubmitLockAspect resubmitLockAspect(DistributedLockService distributedLockService){
return new ResubmitLockAspect(distributedLockService);
}
@Bean
public RedisCacheAspect redisCacheAspect(){
return new RedisCacheAspect();
}
@Bean
public LockKeyGenerator lockKeyGenerator(){
return new DistributedLockKeyGenerator();
}
@Bean
public DistributedLockService distributedLockService(RedissonClient redissonClient){
return new DistributedLockServiceImpl(redissonClient);
}
@Bean
public AbstractDistributeLockSupport<RLock> distributeLockSupport(RedissonClient redissonClient){
return new RedisDistributeLockSupport(redissonClient);
}
}

View File

@@ -0,0 +1,49 @@
package cn.fateverse.common.lock.annotation;
import cn.fateverse.common.lock.enums.BlockLockType;
import cn.fateverse.common.redis.constant.RedisConstant;
import java.lang.annotation.*;
import java.util.concurrent.TimeUnit;
/**
* @author Clay
* @date 2023-05-10
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface DistributedLock {
/**
* 前缀
*/
String prefix() default "";
/**
* 锁过期时间
*/
int expireTime() default 30;
/**
* 获取锁等待时间
*/
int waitTime() default 10;
/**
* 时间单位
*/
TimeUnit timeUnit() default TimeUnit.SECONDS;
/**
* 分隔符
*/
String delimiter() default RedisConstant.REDIS_SEPARATOR;
/**
* 锁类型
*/
BlockLockType lock() default BlockLockType.COMMON;
}

View File

@@ -0,0 +1,18 @@
package cn.fateverse.common.lock.annotation;
import java.lang.annotation.*;
/**
* 参数注解
*
* @author Clay
* @date 2023-05-10
*/
@Target({ElementType.PARAMETER, ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface DistributedLockParam {
String name() default "";
}

View File

@@ -0,0 +1,59 @@
package cn.fateverse.common.lock.annotation;
import java.lang.annotation.*;
import java.util.concurrent.TimeUnit;
/**
*
* 防止重复提交注解
* 1、当设置了keys时通过表达式确定取哪几个参数作为防重key
* 2、当未设置keys时可以设置argsIndex设置取哪几个参数作为防重key
* 3、argsIndex和ignoreKeys是未设置keys时生效排除不需要防重的参数
*
* @author Clay
* @date 2023-05-10
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ResubmitLock {
/**
* 防重复提交校验的时间间隔
*/
long interval() default 5;
/**
* 防重复提交校验的时间间隔的单位
*/
TimeUnit timeUnit() default TimeUnit.SECONDS;
/**
* 是否选用当前操作用户的信息作为防重复提交校验key的一部分
*/
boolean currentUser() default true;
/**
* keys和ignoreKeys不能同时使用
* 参数Spring EL表达式例如 #{param.name},表达式的值作为防重复校验key的一部分
*/
String[] keys() default {};
/**
* keys和ignoreKeys不能同时使用
* ignoreKeys不区分入参所有入参拥有相同的字段时都将过滤掉
*/
String[] ignoreKeys() default {};
/**
* Spring EL表达式,决定是否进行重复提交校验,多个条件之间为且的关系,默认是进行校验
*/
String[] conditions() default {"true"};
/**
* 当未配置key时设置哪几个参数作为防重对象默认取所有参数
*
* @return
*/
int[] argsIndex() default {};
}

View File

@@ -0,0 +1,91 @@
package cn.fateverse.common.lock.aspect;
import cn.fateverse.common.lock.annotation.DistributedLock;
import cn.fateverse.common.lock.enums.BlockLockType;
import cn.fateverse.common.lock.service.LockKeyGenerator;
import cn.hutool.core.util.StrUtil;
import cn.fateverse.common.core.exception.CustomException;
import cn.fateverse.common.redis.constant.RedisConstant;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.core.annotation.Order;
/**
* 分布式锁切面类
* redis 中缓存key说明:
*
* @author Clay
* @date 2023-05-10
*/
@Aspect
@Order(4)
@Slf4j
@ConditionalOnProperty(name = "enabled", prefix = "redis.distributed-lock", havingValue = "true", matchIfMissing = true)
public class DistributedLockAspect {
//redis使用分隔符
private static final String REDIS_SEPARATOR = RedisConstant.REDIS_SEPARATOR;
//redis缓存全局前缀
private static final String DISTRIBUTED_CHECK_KEY_PREFIX = "distributed_lock" + REDIS_SEPARATOR;
private final RedissonClient redissonClient;
private final LockKeyGenerator lockKeyGenerator;
public DistributedLockAspect(RedissonClient redissonClient,
LockKeyGenerator lockKeyGenerator) {
this.redissonClient = redissonClient;
this.lockKeyGenerator = lockKeyGenerator;
}
@Around("@within(distributedLock) || @annotation(distributedLock)")
public Object distributedLockCheck(ProceedingJoinPoint point, DistributedLock distributedLock) throws Throwable {
if (StrUtil.isEmpty(distributedLock.prefix())) {
throw new CustomException("lock prefix can't be null...");
}
//获取到lock的关键词
String lockKey = DISTRIBUTED_CHECK_KEY_PREFIX + lockKeyGenerator.getLockKey(point, distributedLock);
//获取到锁
RLock lock = chooseLock(distributedLock, lockKey);
boolean lockSuccess = false;
Object proceed = null;
try {
lockSuccess = lock.tryLock(distributedLock.waitTime(), distributedLock.expireTime(), distributedLock.timeUnit());
if (lockSuccess) {
proceed = point.proceed();
} else {
log.debug("tryLock success key [{}]", lockKey);
throw new CustomException("系统繁忙,请稍后再试");
}
} catch (InterruptedException e) {
log.error("key is : {" + lockKey + "} tryLock error ", e);
throw new CustomException("系统繁忙,请稍后再试");
} finally {
if (lockSuccess) {
lock.unlock();
}
}
return proceed;
}
private RLock chooseLock(DistributedLock distributedLock, String lockKey) {
BlockLockType category = distributedLock.lock();
switch (category) {
case FAIR:
return redissonClient.getFairLock(lockKey);
case SPIN:
return redissonClient.getSpinLock(lockKey);
case COMMON:
return redissonClient.getLock(lockKey);
default:
throw new CustomException("锁类型错误");
}
}
}

View File

@@ -0,0 +1,115 @@
package cn.fateverse.common.lock.aspect;
import cn.fateverse.common.core.constant.UserConstants;
import cn.fateverse.common.core.enums.ResultEnum;
import cn.fateverse.common.core.exception.CustomException;
import cn.fateverse.common.core.utils.HttpServletUtils;
import cn.fateverse.common.core.utils.IpUtils;
import cn.fateverse.common.core.utils.ReflectUserUtils;
import cn.fateverse.common.lock.annotation.ResubmitLock;
import cn.fateverse.common.lock.service.DistributedLockService;
import cn.fateverse.common.redis.constant.RedisConstant;
import cn.fateverse.common.redis.utils.ExpressionUtils;
import cn.fateverse.common.redis.utils.KeyUtils;
import lombok.NonNull;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.expression.EvaluationContext;
import org.springframework.security.core.context.SecurityContextHolder;
import javax.servlet.http.HttpServletRequest;
/**
* 防重复提交切面类
* redis 中缓存key说明:
* resubmit_lock(全局缓存前缀) + 用户信息(开启用户配置才会添加) + ip地址 + uri + 参数形成的md5唯一秘钥
*
* @author Clay
* @date 2023-05-10
*/
@Slf4j
@Aspect
@ConditionalOnProperty(name = "enabled", prefix = "redis.resubmit-lock", havingValue = "true", matchIfMissing = true)
public class ResubmitLockAspect {
//redis使用分隔符
private static final String REDIS_SEPARATOR = RedisConstant.REDIS_SEPARATOR;
//redis缓存全局前缀
private static final String RESUBMIT_CHECK_KEY_PREFIX = "resubmit_lock" + REDIS_SEPARATOR;
private final DistributedLockService distributedLockService;
public ResubmitLockAspect(DistributedLockService distributedLockService) {
this.distributedLockService = distributedLockService;
}
@SneakyThrows
@Before("@within(resubmitLock) || @annotation(resubmitLock)")
public void resubmitCheck(JoinPoint joinPoint, ResubmitLock resubmitLock) {
// 获取方法签名
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
// 获取参数名称
String[] parameterNames = methodSignature.getParameterNames();
final Object[] args = joinPoint.getArgs();
final String[] conditions = resubmitLock.conditions();
EvaluationContext context = ExpressionUtils.getEvaluationContext(args, parameterNames);
//根据条件判断是否需要进行防重复提交检查
if (!ExpressionUtils.getConditionValue(context, conditions) || ArrayUtils.isEmpty(args)) {
return;
}
doCheck(resubmitLock, args, context);
}
/**
* key的组成为: resubmit_lock:userId:sessionId:uri:method:(根据spring EL表达式对参数进行拼接)
*
* @param resubmitLock 注解
* @param args 方法入参
*/
private void doCheck(@NonNull ResubmitLock resubmitLock, Object[] args, EvaluationContext context) {
//配置的key
final String[] keys = resubmitLock.keys();
//获取到请求
HttpServletRequest request = HttpServletUtils.getRequest();
//获取到方法
String method = request.getMethod();
//获取到uri
String uri = request.getRequestURI();
//获取到锁的关键词
StringBuilder lockKeyBuffer = new StringBuilder(RESUBMIT_CHECK_KEY_PREFIX);
//获取用户信息
Object loginUser = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
//锁类型使用用户信息,并且用户信息存在,则将用户信息加到key中,若为匿名用户则将用户客户端的ip作为key
if (resubmitLock.currentUser() && null != loginUser && !UserConstants.ANONYMOUS_USER.equals(loginUser)) {
lockKeyBuffer.append(ReflectUserUtils.getToken(loginUser)).append(REDIS_SEPARATOR);
} else {
String ipAdder = IpUtils.getIpAdder(request);
lockKeyBuffer.append(ipAdder).append(REDIS_SEPARATOR);
}
//将uri和请求类型放入
lockKeyBuffer.append(uri).append(REDIS_SEPARATOR).append(method);
// 将请求参数取md5值作为key的一部分MD5理论上会重复但是key中还包含session或者用户id所以同用户在极端时间内请参数不同生成的相同md5值的概率极低
String parametersKey = KeyUtils.getParametersKey(args, keys, resubmitLock.ignoreKeys(), resubmitLock.argsIndex(), REDIS_SEPARATOR, context);
lockKeyBuffer.append(parametersKey);
//进行锁的判断
try {
//尝试获取锁,等待时间为0,立即返回
boolean isLock = distributedLockService.tryLock(lockKeyBuffer.toString(), 0, resubmitLock.interval(), resubmitLock.timeUnit());
if (!isLock) {
//没有获取到则视为重复提交
throw new CustomException(ResultEnum.RESUBMIT_LOCK.msg, ResultEnum.RESUBMIT_LOCK.code);
}
//发生异常也视为重复提交
} catch (InterruptedException e) {
throw new CustomException(ResultEnum.RESUBMIT_LOCK.msg, ResultEnum.RESUBMIT_LOCK.code);
}
}
}

View File

@@ -0,0 +1,104 @@
package cn.fateverse.common.lock.base;
import cn.fateverse.common.lock.enums.DistributeLockType;
import java.util.concurrent.TimeUnit;
/**
* @author Clay
* @date 2023-05-10
*/
public class DistributeLockParam {
/**
* 锁id
*/
private String lockUuid;
/**
* 锁前缀
*/
private String lockNamePrefix;
/**
* 过期时间
*/
private Long expireTime;
/**
* 等待时间
*/
private Long waitTime;
/**
* 时间单位
*/
private TimeUnit timeUnit;
/**
* 间隔符
*/
private String delimiter;
/**
* 锁类型
*/
private DistributeLockType lockType;
public String getLockUuid() {
return lockUuid;
}
public void setLockUuid(String lockUuid) {
this.lockUuid = lockUuid;
}
public String getLockNamePrefix() {
return lockNamePrefix;
}
public void setLockNamePrefix(String lockNamePrefix) {
this.lockNamePrefix = lockNamePrefix;
}
public Long getExpireTime() {
return expireTime;
}
public void setExpireTime(Long expireTime) {
this.expireTime = expireTime;
}
public Long getWaitTime() {
return waitTime;
}
public void setWaitTime(Long waitTime) {
this.waitTime = waitTime;
}
public TimeUnit getTimeUnit() {
return timeUnit;
}
public void setTimeUnit(TimeUnit timeUnit) {
this.timeUnit = timeUnit;
}
public String getDelimiter() {
return delimiter;
}
public void setDelimiter(String delimiter) {
this.delimiter = delimiter;
}
public DistributeLockType getLockType() {
return lockType;
}
public void setLockType(DistributeLockType lockType) {
this.lockType = lockType;
}
}

View File

@@ -0,0 +1,24 @@
package cn.fateverse.common.lock.enums;
/**
* 锁类型
*
* @author Clay
* @date 2023-05-10
*/
public enum BlockLockType {
/**
* 统一锁
*/
COMMON,
/**
* 平凡锁
*/
SPIN,
/**
* 可重入失败锁
*/
FAIR;
}

View File

@@ -0,0 +1,35 @@
package cn.fateverse.common.lock.enums;
/**
* @author Clay
* @date 2023-05-10
*/
public enum DistributeLockType {
/**
* 重入锁
*/
REENTRANT_LOCK,
/**
* 非公平锁
*/
FAIR_LOCK,
/**
* 联和锁
*/
MULTI_LOCK,
/**
* 红锁
*/
RED_LOCK,
/**
* 读写锁
*/
READ_WRITE_LOCK,
;
}

View File

@@ -0,0 +1,46 @@
package cn.fateverse.common.lock.service;
import cn.fateverse.common.lock.base.DistributeLockParam;
import cn.fateverse.common.redis.constant.RedisConstant;
import com.google.common.base.Joiner;
/**
* 分布式锁的接口
*
* @author Clay
* @date 2023-05-10
*/
public interface DistributeLockSupport<T> {
/**
* 默认的分隔符
*/
String DEFAULT_DELIMITER = RedisConstant.REDIS_SEPARATOR;
String DEFAULT_KEY_PREFIX = "LOCK";
Long DEFAULT_EXPIRE_TIME = 10L;
Long DEFAULT_WAIT_TIME = 10L;
Joiner DEFAULT_JOINER = Joiner.on(DistributeLockSupport.DEFAULT_DELIMITER).
skipNulls();
/**
* 加锁
*
* @param distributeLockParam 锁参数
* @return 返回锁
*/
T lock(DistributeLockParam distributeLockParam);
/**
* 解锁
*
* @param lock 锁
*/
void unlock(T lock);
}

View File

@@ -0,0 +1,78 @@
package cn.fateverse.common.lock.service;
import org.redisson.api.RLock;
import java.util.concurrent.TimeUnit;
/**
* 分布式锁接口
* @author Clay
* @date 2023-05-10
*/
public interface DistributedLockService {
/**
* 加锁
* @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-获取锁失败
* @throws InterruptedException
*/
boolean tryLock(String lockKey, long waitTime, long leaseTime, TimeUnit unit)
throws InterruptedException;
/**
* 锁是否被任意一个线程锁持有
* @param lockKey
* @return true-被锁 false-未被锁
*/
boolean isLocked(String lockKey);
RLock getLock(String lockKey);
RLock getFairLock(String lockKey);
}

View File

@@ -0,0 +1,24 @@
package cn.fateverse.common.lock.service;
import cn.fateverse.common.lock.annotation.DistributedLock;
import org.aspectj.lang.ProceedingJoinPoint;
/**
* 锁的关键词生成接口
*
* @author Clay
* @date 2023-05-10
*/
public interface LockKeyGenerator {
/**
* 获取自定义锁
*
* @param point aop切点
* @param lock 锁注解
* @return 锁关键词
*/
String getLockKey(ProceedingJoinPoint point, DistributedLock lock);
}

View File

@@ -0,0 +1,64 @@
package cn.fateverse.common.lock.service.impl;
import cn.fateverse.common.lock.base.DistributeLockParam;
import cn.fateverse.common.lock.enums.DistributeLockType;
import cn.fateverse.common.lock.service.DistributeLockSupport;
import com.google.common.base.Joiner;
import com.google.common.base.Preconditions;
import org.apache.commons.lang3.StringUtils;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
/**
* @author Clay
* @date 2023-05-10
*/
public abstract class AbstractDistributeLockSupport<T> implements DistributeLockSupport<T> {
/**
* 检验参数
*
* @param distributeLockParam 锁参数
* @return 锁参数
*/
protected DistributeLockParam fullDistributeDefaultValue(DistributeLockParam distributeLockParam) {
Preconditions.checkNotNull(distributeLockParam, "检测到了参数不允许为空!");
//对默认值进行填充
distributeLockParam.setLockType(Optional.ofNullable(distributeLockParam.getLockType()).orElse(DistributeLockType.FAIR_LOCK));
distributeLockParam.setExpireTime(Optional.ofNullable(distributeLockParam.getExpireTime()).orElse(DEFAULT_EXPIRE_TIME));
distributeLockParam.setWaitTime(Optional.ofNullable(distributeLockParam.getExpireTime()).orElse(DEFAULT_WAIT_TIME));
distributeLockParam.setTimeUnit(Optional.ofNullable(distributeLockParam.getTimeUnit()).orElse(TimeUnit.SECONDS));
return distributeLockParam;
}
/**
* 构建相关的锁key值
*
* @param distributeLockParam 锁参数
* @return 锁key
*/
protected String buildLockKey(DistributeLockParam distributeLockParam) {
String lockId = StringUtils.defaultIfEmpty(distributeLockParam.getLockUuid(),
java.util.UUID.randomUUID().toString());
distributeLockParam.setLockUuid(lockId);
String delmiter = StringUtils.defaultIfEmpty(distributeLockParam.getDelimiter(),
DEFAULT_DELIMITER);
distributeLockParam.setDelimiter(delmiter);
String prefix = StringUtils.defaultIfEmpty(distributeLockParam
.getLockNamePrefix(), DEFAULT_KEY_PREFIX);
distributeLockParam.setLockNamePrefix(prefix);
String lockFullName = "";
if (!delmiter.equals(DEFAULT_DELIMITER)) {
//todo 待优化
Joiner joiner = Joiner.on(delmiter).skipNulls();
lockFullName = joiner.join(prefix, lockId);
} else {
lockFullName = DEFAULT_JOINER.join(prefix, lockId);
}
return lockFullName;
}
}

View File

@@ -0,0 +1,62 @@
package cn.fateverse.common.lock.service.impl;
import cn.fateverse.common.lock.annotation.DistributedLockParam;
import cn.fateverse.common.lock.service.LockKeyGenerator;
import cn.hutool.core.util.StrUtil;
import cn.fateverse.common.lock.annotation.DistributedLock;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.util.ReflectionUtils;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
/**
* @author Clay
* @date 2023-05-10
*/
@Slf4j
public class DistributedLockKeyGenerator implements LockKeyGenerator {
@Override
public String getLockKey(ProceedingJoinPoint point, DistributedLock lock) {
MethodSignature signature = (MethodSignature)point.getSignature();
//获取请求参数
Object[] args = point.getArgs();
//获取方法
Method method = signature.getMethod();
//获取方法参数
Parameter[] parameters = method.getParameters();
//锁
StringBuilder lockBuilder = new StringBuilder();
//默认解析方法里面带 CacheParam 注解的属性,如果没有尝试着解析实体对象中的
for (int i = 0; i < parameters.length; i++) {
Parameter parameter = parameters[i];
DistributedLockParam annotation = parameter.getAnnotation(DistributedLockParam.class);
if (null == annotation){
continue;
}
lockBuilder.append(lock.delimiter()).append(args[i]);
}
//如果获取到参数为空,则检查对象中是否存在当前注解
if (StrUtil.isEmpty(lockBuilder.toString())){
Annotation[][] parameterAnnotations = method.getParameterAnnotations();
for (int i = 0; i < parameterAnnotations.length; i++) {
Object arg = args[i];
Field[] fields = arg.getClass().getDeclaredFields();
for (Field field : fields) {
DistributedLockParam annotation = field.getAnnotation(DistributedLockParam.class);
if (null == annotation){
continue;
}
field.setAccessible(true);
lockBuilder.append(lock.delimiter()).append(ReflectionUtils.getField(field,arg));
}
}
}
return lock.prefix() + lock;
}
}

View File

@@ -0,0 +1,72 @@
package cn.fateverse.common.lock.service.impl;
import cn.fateverse.common.lock.service.DistributedLockService;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import java.util.concurrent.TimeUnit;
/**
* 分布式锁的 Redisson 接口实现
* @author GitEgg
* @date 2022-4-10
*/
public class DistributedLockServiceImpl implements DistributedLockService {
private final RedissonClient redissonClient;
public DistributedLockServiceImpl(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 timeout) {
RLock lock = redissonClient.getLock(lockKey);
lock.lock(timeout, 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();
}
@Override
public RLock getLock(String lockKey) {
return redissonClient.getLock(lockKey);
}
@Override
public RLock getFairLock(String lockKey) {
return redissonClient.getFairLock(lockKey);
}
}

View File

@@ -0,0 +1,63 @@
package cn.fateverse.common.lock.service.impl;
import cn.fateverse.common.core.exception.CustomException;
import cn.fateverse.common.lock.base.DistributeLockParam;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
/**
* 非阻塞分布式锁的具体实现
*
* @author Clay
* @date 2023-05-10
*/
@Slf4j
public class RedisDistributeLockSupport extends AbstractDistributeLockSupport<RLock> {
private final RedissonClient redissonClient;
public RedisDistributeLockSupport(RedissonClient redissonClient) {
this.redissonClient = redissonClient;
}
@Override
public RLock lock(DistributeLockParam distributeLockParam) {
distributeLockParam = fullDistributeDefaultValue(distributeLockParam);
String lockKey = buildLockKey(distributeLockParam);
RLock lock;
try {
switch (distributeLockParam.getLockType()) {
// 可重入锁
case REENTRANT_LOCK:
lock = redissonClient.getLock(lockKey);
break;
// 非公平锁
case FAIR_LOCK:
lock = redissonClient.getFairLock(lockKey);
break;
default: {
throw new UnsupportedOperationException("暂时不支持此种方式的锁!");
}
}
boolean locked = lock.tryLock(distributeLockParam.getWaitTime(), distributeLockParam.getExpireTime(), distributeLockParam.getTimeUnit());
if (locked){
return lock;
}else {
throw new CustomException("获取锁失败");
}
} catch (InterruptedException e) {
log.error("加锁为阻塞模式下的锁进行失败!", e);
throw new CustomException("获取锁失败");
}
}
@Override
public void unlock(RLock lock) {
try {
lock.unlock();
} catch (Exception e) {
log.error("解锁为阻塞模式下的锁进行失败!", e);
}
}
}

View File

@@ -0,0 +1 @@
cn.fateverse.common.lock.RedisAutoConfiguration