首先,添加注解
package com.jsbiot.biz.common.annotation;
import org.springframework.core.annotation.AliasFor;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.concurrent.TimeUnit;
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface RedisLock {
String type() default "";
String key() default "";
@AliasFor("key")
String value() default "";
long waitTime() default 5;
long leaseTime() default 30;
TimeUnit unit() default TimeUnit.SECONDS;
}
注解要用的增强类
package com.jsbiot.biz.common.aspect;
import com.jsbiot.biz.common.annotation.RedisLock;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.lang.reflect.Method;
import java.util.concurrent.TimeUnit;
@Slf4j
@Aspect
@Component
public class RedisLockAspect {
@Resource
private RedissonClient redissonClient;
private final SpelExpressionParser parser = new SpelExpressionParser();
private final DefaultParameterNameDiscoverer discoverer = new DefaultParameterNameDiscoverer();
@Around("@annotation(com.jsbiot.biz.common.annotation.RedisLock)")
public Object aroundMethod(ProceedingJoinPoint pjp) throws Throwable {
Object object = null;
MethodSignature joinPointObject = (MethodSignature) pjp.getSignature();
Method method = joinPointObject.getMethod();
RedisLock redisLock = method.getAnnotation(RedisLock.class);
if(null == redisLock) {
return pjp.proceed();
}
Object[] args = pjp.getArgs();
String[] params = discoverer.getParameterNames(method);
EvaluationContext context = new StandardEvaluationContext();
if (params != null) {
for (int i = 0; i < params.length; i++) {
context.setVariable(params[i],args[i]);
}
}
//带#使用spel获取方法参数,不带则使用key原始值
String key = redisLock.key();
if(StringUtils.isNotBlank(key) && key.contains("#")){
Expression keyExpression = parser.parseExpression(key);
key = keyExpression.getValue(context,String.class);
}
key = StringUtils.isNotBlank(redisLock.type())?redisLock.type()+key:key;
RLock lock = redissonClient.getLock(key);
long waitTime = redisLock.waitTime();
long leaseTime = redisLock.leaseTime();
TimeUnit unit = redisLock.unit();
try {
if(lock.tryLock(waitTime,leaseTime,unit)) {
object = pjp.proceed();
}
} catch (Exception e) {
throw e;
} finally {
//锁被持有,并且被当前线程持有
if (lock.isLocked() && lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
return object;
}
}