分布式锁的注解
起因
如果我每个方法的要做分布式的锁进行锁,解锁,都要写一段相似的代码,选取key,上锁,try,解锁。这样的话,很烦诶。
那么相似的代码,就很简单的能利用aop来解决。
开搞
注解
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface MyRedissonLock {
String nameSpace() default "";
/**
* key
*/
String key() default "";
TimeUnit timeUnit() default TimeUnit.SECONDS;
long waitTime() default -1L;
long leaseTime() default -1L;
}
aop
package com.xy.microservice.system.aop;
import com.google.gson.Gson;
import com.xy.microservice.common.annotation.MyRedissonLock;
import com.xy.microservice.common.utils.StringUtil;
import com.xy.microservice.system.utils.redisson.RedissonDistributedLocker;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
import java.util.concurrent.TimeUnit;
/**
* @description: redisson的aop实现
* @author: wzy
* @create: 2021-01-23 17:43
**/
@Aspect
@Component
@Slf4j
public class RedissonLockAspect {
@Autowired
RedissonDistributedLocker redissonDistributedLocker;
private String nameSpace;
private String key;
TimeUnit timeUnit;
private long leaseTime;
private long waitTime;
//截获标有@RedisPut
@Pointcut(value = "(execution(* *.*(..)) && @annotation(com.xy.microservice.common.annotation.MyRedissonLock))")
public void pointcut() {
}
// 在使用@RedisPut注解的地方织入此切点
@Around(value = "pointcut()")
private Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
Method m = ((MethodSignature) proceedingJoinPoint.getSignature()).getMethod();
// this()返回代理对象,target()返回目标对象,目标对象反射获取的method对象才包含注解
Method methodWithAnnotations = proceedingJoinPoint.getTarget().getClass().getDeclaredMethod(
proceedingJoinPoint.getSignature().getName(), m.getParameterTypes());
Object[] args = proceedingJoinPoint.getArgs();
// 根据目标方法对象获取注解对象
MyRedissonLock annotation = methodWithAnnotations.getDeclaredAnnotation(MyRedissonLock.class);
nameSpace = StringUtil.isEmptyString(annotation.nameSpace()) ? m.getName() : annotation.nameSpace();
key = StringUtil.isEmptyString(annotation.key()) ? getArgsHash(args) : parseKey(methodWithAnnotations, args, annotation.key());
timeUnit = annotation.timeUnit();
waitTime = annotation.waitTime();
leaseTime = annotation.leaseTime();
getLock(nameSpace, key, timeUnit, leaseTime, waitTime);
Object result = null;
result = proceedingJoinPoint.proceed(args);
return result;
}
@After("pointcut()")
public void doAfter() {
doUnLock(nameSpace, key);
}
private void getLock(String nameSpace, String key, TimeUnit timeUnit, long leaseTime, long waitTime) {
String lockKey = nameSpace + ":" + key;
if (leaseTime == -1 && waitTime == -1) {
redissonDistributedLocker.lock(lockKey);
} else if (leaseTime == -1) {
redissonDistributedLocker.lock(lockKey, timeUnit, waitTime);
} else {
redissonDistributedLocker.tryLock(lockKey, timeUnit, waitTime, leaseTime);
}
}
private void doUnLock(String nameSpace, String key) {
String lockKey = nameSpace + ":" + key;
redissonDistributedLocker.unlock(lockKey);
}
private String getArgsHash(Object[] args) {
if (args == null || args.length == 0) return String.valueOf(Object.class.hashCode());
StringBuffer sb = new StringBuffer();
Gson gson = new Gson();
for (Object arg : args) {
sb.append(gson.toJson(arg).hashCode());
}
return sb.toString();
}
//解析springEL表达式 有nameSpaceExtend的前缀或者无nameSpaceExtend的key
private String parseKey(Method method, Object[] argValues, String keyEl) {
//创建解析器
ExpressionParser parser = new SpelExpressionParser();
// 参数
EvaluationContext context = new StandardEvaluationContext();
LocalVariableTableParameterNameDiscoverer discover = new LocalVariableTableParameterNameDiscoverer();
String[] parameterNames = discover.getParameterNames(method);
for (int i = 0; i < parameterNames.length; i++) {
context.setVariable(parameterNames[i], argValues[i]);
}
Expression expression = parser.parseExpression(keyEl);
// 解析
return expression.getValue(context).toString();
}
}
简简单单