使用Redission实现优雅的分布式锁的使用
定义注解
public @interface DistributeLock {
/**
* 锁的场景
*/
public String scene() default DistributeLockConstant.DEFAULT_SCENE;
/**
* 加锁的key,优先取key(),如果没有,则取keyExpression()
*/
public String key() default DistributeLockConstant.NONE_KEY;
/**
* SPEL表达式:
*/
public String keyExpression() default DistributeLockConstant.NONE_KEY;
/**
* 超时时间,毫秒
* 默认情况下不设置超时时间,会自动续期
*/
public int expireTime() default DistributeLockConstant.DEFAULT_EXPIRE_TIME;
/**
* 加锁等待时长,毫秒
* 默认情况下不设置等待时长,不做等待
*/
public int waitTime() default DistributeLockConstant.DEFAULT_WAIT_TIME;
}
实现一个utils去解析SPEL
public class SPelUtil {
private static final ExpressionParser parser = new SpelExpressionParser();
private static final StandardReflectionParameterNameDiscoverer parameterNameDiscoverer = new StandardReflectionParameterNameDiscoverer();
public static String parseSpEl(Method method, Object[] args, String spEl) {
String[] params = Optional.ofNullable(parameterNameDiscoverer.getParameterNames(method)).orElse(new String[]{});//解析参数名
EvaluationContext context = new StandardEvaluationContext();//el解析需要的上下文对象
for (int i = 0; i < params.length; i++) {
context.setVariable(params[i], args[i]);//所有参数都作为原材料扔进去
}
Expression expression = parser.parseExpression(spEl);
return expression.getValue(context, String.class);
}
public static String getLockKey(String perFix , String key){
return perFix + key;
}
}
实现切面逻辑
@Aspect
@Component
public class DistributeLockAspect {
private RedissonClient redissonClient;
public DistributeLockAspect(RedissonClient redissonClient) {
this.redissonClient = redissonClient;
}
private static final Logger LOG = LoggerFactory.getLogger(DistributeLockAspect.class);
@Around("@annotation(DistributeLock)")
public Object process(ProceedingJoinPoint pjp) throws Exception {
Object response = null;
Method method = ((MethodSignature) pjp.getSignature()).getMethod();
DistributeLock distributeLock = method.getAnnotation(DistributeLock.class);
String key = distributeLock.key();
if (DistributeLockConstant.NONE_KEY.equals(key)) {
if (DistributeLockConstant.NONE_KEY.equals(distributeLock.keyExpression())) {
throw new DistributeLockException("no lock key found...");
}
// 获取参数值
Object[] args = pjp.getArgs();
key = SPelUtil.parseSpEl(method, args, distributeLock.keyExpression());
}
// 默认取方法名称作为分布式锁的key
String scene = Optional.ofNullable(distributeLock.scene()).orElse(method.getName());
String lockKey = scene + "#" + key;
int expireTime = distributeLock.expireTime();
int waitTime = distributeLock.waitTime();
RLock rLock = redissonClient.getLock(lockKey);
boolean lockResult = lockResult = rLock.tryLock(waitTime, expireTime, TimeUnit.MILLISECONDS);;
if (!lockResult) {
LOG.warn(String.format("lock failed for key : %s , expire : %s", lockKey, expireTime));
throw new DistributeLockException("acquire lock failed... key : " + lockKey);
}
try {
LOG.info(String.format("lock success for key : %s , expire : %s", lockKey, expireTime));
response = pjp.proceed();
} catch (Throwable e) {
throw new Exception(e);
} finally {
rLock.unlock();
LOG.info(String.format("unlock for key : %s , expire : %s", lockKey, expireTime));
}
return response;
}
}