跳到主要内容

一个注解实现分布式锁

定义Redis分布式锁注解

/**
* redisson分布式锁注解
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface RedissonLock {
/**
* key的前缀,默认取方法名
*
* @return
*/
String prefix() default "";

/**
* 支持spring EL表达式
*
* @return
*/
String key();

/**
* 等待锁的排队事件,默认-1,快速失败
*
* @return
*/
int waitTime() default -1;

/**
* 时间单位,默认毫秒
*
* @return
*/
TimeUnit unit() default TimeUnit.MILLISECONDS;

}

定义分布式锁的切面

@Component
@Aspect
@Order(0) // 保证在事务之前执行,分布式锁需要在事务之前执行
public class RedissonLockAspect {

@Resource
private LockService lockService;

@Around("@annotation(com.yunfei.codegenie.common.annotation.RedissonLock)")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
Signature signature = joinPoint.getSignature();
MethodSignature signature1 = (MethodSignature) signature;
Method method = signature1.getMethod();
RedissonLock redissonLock = method.getAnnotation(RedissonLock.class);
String prefix = StrUtil.isBlank(redissonLock.prefix()) ? SpElUtils.getMethodKey(method) : redissonLock.prefix();
String key = SpElUtils.parseSpEl(method, joinPoint.getArgs(), redissonLock.key());
return lockService.executeWithLock(prefix + ":" + key, redissonLock.waitTime(), redissonLock.unit(), joinPoint::proceed);
}
}

具体实现逻辑

@Service
@Slf4j
public class LockService {

@Resource
private RedissonClient redissonClient;

public <T> T executeWithLockThrows(String key, int waitTime, TimeUnit unit, SupplierThrow<T> supplier) throws Throwable {
RLock lock = redissonClient.getLock(key);
boolean lockSuccess = lock.tryLock(waitTime, unit);
if (!lockSuccess) {
throw new BusinessException(Code.LOCK_LIMIT);
}
try {
return supplier.get();// 执行锁内的代码逻辑
} finally {
if (lock.isLocked() && lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
}

@SneakyThrows
public <T> T executeWithLock(String key, int waitTime, TimeUnit unit, SupplierThrow<T> supplier) {
return executeWithLockThrows(key, waitTime, unit, supplier::get);
}

public <T> T executeWithLock(String key, SupplierThrow<T> supplier) {
return executeWithLock(key, -1, TimeUnit.MILLISECONDS, supplier);
}

@FunctionalInterface
public interface SupplierThrow<T> {

/**
* Gets a result.
*
* @return a result
*/
T get() throws Throwable;
}
}

EL表达式工具类

/**
* Description: spring el表达式解析
*/
public class SpElUtils {
private static final ExpressionParser parser = new SpelExpressionParser();
private static final DefaultParameterNameDiscoverer parameterNameDiscoverer = new DefaultParameterNameDiscoverer();

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 getMethodKey(Method method) {
return method.getDeclaringClass() + "#" + method.getName();
}
}