Docker 系统性入门+进阶实践(2021最新版)
超级架构师可能是最好的Redis散布式锁完成
1、引入redisson依赖
org.redisson
redisson
3.16.2
Copy to clipboardErrorCopied
复制代码
2、自定义注解
/**
* 散布式锁自定义注解
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Lock {
/**
* 锁的形式:假如不设置自动形式,当参数只要一个.运用 REENTRANT 参数多个 MULTIPLE
*/
LockModel lockModel() default LockModel.AUTO;
/**
* 假如keys有多个,假如不设置,则运用 联锁
*
* @return
*/
String[] keys() default {};
/**
* key的静态常量:当key的spel的值是LIST、数组时运用+号衔接将会被spel以为这个变量是个字符串,只能产生一把锁,达不到我们的目的,
* 而我们假如又需求一个常量的话。这个参数将会在拼接在每个元素的后面
*
* @return
*/
String keyConstant() default "";
/**
* 锁超时时间,默许30000毫秒(可在配置文件全局设置)
*
* @return
*/
long watchDogTimeout() default 30000;
/**
* 等候加锁超时时间,默许10000毫秒 -1 则表示不断等候(可在配置文件全局设置)
*
* @return
*/
long attemptTimeout() default 10000;
}
复制代码
3、常量类
/**
* Redisson常量类
*/
public class RedissonConst {
/**
* redisson锁默许前缀
*/
public static final String REDISSON_LOCK = "redisson:lock:";
/**
* spel表达式占位符
*/
public static final String PLACE_HOLDER = "#";
}
复制代码
4、枚举
/**
* 锁的形式
*/
public enum LockModel {
/**
* 可重入锁
*/
REENTRANT,
/**
* 公平锁
*/
FAIR,
/**
* 联锁
*/
MULTIPLE,
/**
* 红锁
*/
RED_LOCK,
/**
* 读锁
*/
READ,
/**
* 写锁
*/
WRITE,
/**
* 自动形式,当参数只要一个运用 REENTRANT 参数多个 RED_LOCK
*/
AUTO
}
复制代码
5、自定义异常
/**
* 散布式锁异常
*/
public class ReddissonException extends RuntimeException {
public ReddissonException() {
}
public ReddissonException(String message) {
super(message);
}
public ReddissonException(String message, Throwable cause) {
super(message, cause);
}
public ReddissonException(Throwable cause) {
super(cause);
}
public ReddissonException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}
复制代码
6、AOP切面
/**
* 散布式锁aop
*/
@Slf4j
@Aspect
public class LockAop {
@Autowired
private RedissonClient redissonClient;
@Autowired
private RedissonProperties redissonProperties;
@Autowired
private LockStrategyFactory lockStrategyFactory;
@Around("@annotation(lock)")
public Object aroundAdvice(ProceedingJoinPoint proceedingJoinPoint, Lock lock) throws Throwable {
// 需求加锁的key数组
String[] keys = lock.keys();
if (ArrayUtil.isEmpty(keys)) {
throw new ReddissonException("redisson lock keys不能为空");
}
// 获取办法的参数名
String[] parameterNames = new LocalVariableTableParameterNameDiscoverer().getParameterNames(((MethodSignature) proceedingJoinPoint.getSignature()).getMethod());
Object[] args = proceedingJoinPoint.getArgs();
// 等候锁的超时时间
long attemptTimeout = lock.attemptTimeout();
if (attemptTimeout == 0) {
attemptTimeout = redissonProperties.getAttemptTimeout();
}
// 锁超时时间
long lockWatchdogTimeout = lock.watchdogTimeout();
if (lockWatchdogTimeout == 0) {
lockWatchdogTimeout = redissonProperties.getLockWatchdogTimeout();
}
// 加锁形式
LockModel lockModel = getLockModel(lock, keys);
if (!lockModel.equals(LockModel.MULTIPLE) && !lockModel.equals(LockModel.RED_LOCK) && keys.length > 1) {
throw new ReddissonException("参数有多个,锁形式为->" + lockModel.name() + ",无法匹配加锁");
}
log.info("锁形式->{},等候锁定时间->{}毫秒,锁定最长时间->{}毫秒", lockModel.name(), attemptTimeout, lockWatchdogTimeout);
boolean res = false;
// 战略形式获取redisson锁对象
RLock rLock = lockStrategyFactory.createLock(lockModel, keys, parameterNames, args, lock.keyConstant(), redissonClient);
//执行aop
if (rLock != null) {
try {
if (attemptTimeout == -1) {
res = true;
//不断等候加锁
rLock.lock(lockWatchdogTimeout, TimeUnit.MILLISECONDS);
} else {
res = rLock.tryLock(attemptTimeout, lockWatchdogTimeout, TimeUnit.MILLISECONDS);
}
if (res) {
return proceedingJoinPoint.proceed();
} else {
throw new ReddissonException("获取锁失败");
}
} finally {
if (res) {
rLock.unlock();
}
}
}
throw new ReddissonException("获取锁失败");
}
/**
* 获取加锁形式
*
* @param lock
* @param keys
* @return
*/
private LockModel getLockModel(Lock lock, String[] keys) {
LockModel lockModel = lock.lockModel();
// 自动形式:优先匹配全局配置,再判别用红锁还是可重入锁
if (lockModel.equals(LockModel.AUTO)) {
LockModel globalLockModel = redissonProperties.getLockModel();
if (globalLockModel != null) {
lockModel = globalLockModel;
} else if (keys.length > 1) {
lockModel = LockModel.RED_LOCK;
} else {
lockModel = LockModel.REENTRANT;
}
}
return lockModel;
}
}
复制代码
这里运用了战略形式来对不同的锁类型提供完成。
7、锁战略的完成
先定义锁战略的笼统基类(也能够用接口):
/**
* 锁战略笼统基类
*/
@Slf4j
abstract class LockStrategy {
@Autowired
private RedissonClient redissonClient;
/**
* 创立RLock
*
* @param keys
* @param parameterNames
* @param args
* @param keyConstant
* @return
*/
abstract RLock createLock(String[] keys, String[] parameterNames, Object[] args, String keyConstant, RedissonClient redissonClient);
/**
* 获取RLock
*
* @param keys
* @param parameterNames
* @param args
* @param keyConstant
* @return
*/
public RLock[] getRLocks(String[] keys, String[] parameterNames, Object[] args, String keyConstant) {
List rLocks = new ArrayList<>();
for (String key : keys) {
List valueBySpel = getValueBySpel(key, parameterNames, args, keyConstant);
for (String s : valueBySpel) {
rLocks.add(redissonClient.getLock(s));
}
}
RLock[] locks = new RLock[rLocks.size()];
int index = 0;
for (RLock r : rLocks) {
locks[index++] = r;
}
return locks;
}
/**
* 经过spring Spel 获取参数
*
* @param key 定义的key值 以#开头 例如:#user
* @param parameterNames 形参
* @param args 形参值
* @param keyConstant key的常亮
* @return
*/
List getValueBySpel(String key, String[] parameterNames, Object[] args, String keyConstant) {
List keys = new ArrayList<>();
if (!key.contains(PLACE_HOLDER)) {
String s = REDISSON_LOCK + key + keyConstant;
log.info("没有运用spel表达式value->{}", s);
keys.add(s);
return keys;
}
// spel解析器
ExpressionParser parser = new SpelExpressionParser();
// spel上下文
EvaluationContext context = new StandardEvaluationContext();
for (int i = 0; i < parameterNames.length; i++) {
context.setVariable(parameterNames[i], args[i]);
}
Expression expression = parser.parseExpression(key);
Object value = expression.getValue(context);
if (value != null) {
if (value instanceof List) {
List valueList = (List) value;
for (Object o : valueList) {
keys.add(REDISSON_LOCK + o.toString() + keyConstant);
}
} else if (value.getClass().isArray()) {
Object[] objects = (Object[]) value;
for (Object o : objects) {
keys.add(REDISSON_LOCK + o.toString() + keyConstant);
}
} else {
keys.add(REDISSON_LOCK + value.toString() + keyConstant);
}
}
log.info("spel表达式key={},value={}", key, keys);
return keys;
}
}