创建redisLock注解:
import java.lang.annotation.Documented;
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;
/**
* redis锁注解
* @author MAZHEN
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
@Documented
public @interface RedisLock {
String lockPrefix() default "";
long timeOut() default 60;
TimeUnit timeUnit() default TimeUnit.SECONDS;
}
拦截器逻辑:
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import org.aspectj.apache.bcel.classfile.Constant;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import com.spring.mongo.annotation.RedisLock;
/**
* redis锁拦截器实现
* @author MAZHEN
*/
@Aspect
@Component
public class RedisLockInterceptor {
private static final Integer MAX_RETRY_COUNT = 10;
private static final String LOCK_PRE_FIX = "lockPreFix";
private static final String TIME_OUT = "timeOut";
@Autowired
private RedisManager redisManager;
@Pointcut("@annotation(com.spring.mongo.annotation.RedisLock)")
public void redisLockAspect(){}
@Around("redisLockAspect()")
public Map<String, Object> lockAroundAction(ProceedingJoinPoint proceeding){
//获取redis锁
Map<String, Object> getLockResult = this.getLock(proceeding,0,System.currentTimeMillis());
}
/**
* 获取锁
* @param proceeding
* @return
*/
private Map<String, Object> getLock(ProceedingJoinPoint proceeding,int count,long currentTime){
//获取注解中的参数
Map<String, Object> annotationArgs = this.getAnnotationArgs(proceeding);
String lockPrefix = (String) annotationArgs.get(LOCK_PRE_FIX);
long expire = (long) annotationArgs.get(TIME_OUT);
String key = this.getFirstArg(proceeding);
if(StringUtils.isEmpty(lockPrefix) || StringUtils.isEmpty(key)){
return this.argErrResult("锁前缀或业务参数不能为空");
}
String lockName = lockPrefix+"_"+key;
String value = String.valueOf(currentTime);
if(CommonRedisUtils.setNx(lockName,value) == 1){
//获取锁成功
CommonRedisUtils.expire(lockName,expire);
return this.buildSuccessResult();
}else {
//获取锁失败,为防止其它线程正在设置过时时间时误删,添加第一个条件
if((System.currentTimeMillis()-currentTime>5000)
&&(CommonRedisUtils.ttl(lockName)<0
||System.currentTimeMillis()-currentTime>expire)){
//强制删除锁,并尝试再次获取锁
CommonRedisUtils.delete(lockName);
if(count<MAX_RETRY_COUNT){
return getLock(proceeding,count++,currentTime);
}
}
return this.buildGetLockErrorResult("请重试!!!");
}
}
/**
* 获取锁参数
* @param proceeding
* @return
*/
private Map<String, Object> getAnnotationArgs(ProceedingJoinPoint proceeding){
Class target = proceeding.getTarget().getClass();
Method[] methods = target.getMethods();
String methodName = proceeding.getSignature().getName();
for (Method method : methods) {
if(method.getName().equals(methodName)){
Map<String, Object> result = new HashMap<String, Object>();
RedisLock redisLock = method.getAnnotation(RedisLock.class);
result.put(LOCK_PRE_FIX,redisLock.lockPrefix());
result.put(TIME_OUT, redisLock.timeUnit().toSeconds(redisLock.timeOut()));
return result;
}
}
return null;
}
/**
* 获取第一个String类型的参数为锁的业务参数
* @param proceeding
* @return
*/
public String getFirstArg(ProceedingJoinPoint proceeding){
Object[] args = proceeding.getArgs();
if(args != null && args.length>0){
for (Object object : args) {
String type = object.getClass().getName();
if("java.lang.String".equals(type)){
return (String)object;
}
}
}
return null;
}
public Map<String, Object> argErrResult(String mes){
Map<String, Object> result = new HashMap<String, Object>();
//TODO
//result.put("code", "9");
result.put("msg", mes);
return result;
}
public Map<String, Object> buildGetLockErrorResult(String mes){
Map<String, Object> result = new HashMap<String, Object>();
//TODO
//result.put("code", "9");
result.put("msg", mes);
return result;
}
public Map<String, Object> buildSuccessResult(){
Map<String, Object> result = new HashMap<String, Object>();
//TODO
//result.put("code", "1");
result.put("msg", "处理成功");
return result;
}
}
使用方式:只需要在需要使用redis锁的方法上添加@RedisLock注解,并输入redis锁的前缀字段,过时时间和时间单位有默认值,而方法上的第一个String类型的参数为锁的key的第二段。