DistributedLock
import java.lang.annotation.*;
/**
* 用于某些方法加分布式的锁特性 其应用于某个方法 ,如果是高并发的带某个唯一参数的方法,常常在该
* 方法的关键参数中添加 @Param("KEYSUFFIX"),只能添加一个 庆主要哦; Param
* 是 mybatis 的那个参数注解(org.apache.ibatis.annotations.Param)
*
*
*/
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface DistributedLock {
public final String PARAMKEY ="KEYSUFFIX";
/**
* 加锁的前缀key 主要用于区分各个业务的方法数据。
* @return
*/
String path() default "";
/**
* 等待时间-毫秒(tryLock时使用)
* @return
*/
long waitTimeOut() default 100 ;
/**
* 只有锁时间-以毫秒为单位
* @return
*/
long leaseTimeOut() default -1 ;
/**
* 是否跟踪(执行时插入一条数据到数据库,并记录执行状态)
* 对加锁延迟敏感的操作建议设置为false,因为插入数据库,并更新执行状态可能会增加延迟
*/
boolean trace() default false;
}
DistributedLockHandler
import com.coinsuper.common.constant.ServiceBusinessExceptionCodeEnum;
import com.coinsuper.common.exception.ServiceBusinessException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.annotations.Param;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
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.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.concurrent.TimeUnit;
/**
* 用于某些方法加分布式的同步锁,需要添加注解 DistributedLockTrait
*
*/
@Component
@Aspect
@Slf4j
public class DistributedLockHandler {
@Autowired
private RedissonClient redission;
/**
* 获取已经加了注解的方法
*
* @param pjp
* @return
* @throws Throwable
*/
@Around(value = "within(*) && @annotation(com.coinsuper.common.lock.support.DistributedLockTrait)")
public Object around(ProceedingJoinPoint pjp) throws Throwable {
Signature signature = pjp.getSignature();
MethodSignature methodSignature = (MethodSignature) signature;
Method targetMethod = methodSignature.getMethod();
DistributedLockTrait redisLockTrait = targetMethod.getDeclaredAnnotation(DistributedLockTrait.class);
String lockPath = getLockKey(pjp);
RLock lock = redission.getLock(lockPath);
boolean locked = false;
Object result = null;
try {
locked = lock.tryLock(redisLockTrait.waitTimeOut(), redisLockTrait.leaseTimeOut(), TimeUnit.MILLISECONDS);
if (locked) {
/** * 处理核心业务的逻辑。 */
result = pjp.proceed();
} else {
log.info("DistributedLockTraitHandler: no distributed lock was obtained.");
throw new ServiceBusinessException(ServiceBusinessExceptionCodeEnum.DISTRIBUTED_LOCK_NOT_GET);
}
} catch (InterruptedException ex) {
log.info(ex.getMessage(), ex);
throw ex;
} catch (Exception e) {
log.info(e.getMessage(), e);
throw e;
} finally {
if (locked) {
lock.unlock();
}
}
return result;
}
/**
* 获取分布式锁的key
*
* @param pjp return
*/
private String getLockKey(ProceedingJoinPoint pjp) {
Signature signature = pjp.getSignature();
MethodSignature methodSignature = (MethodSignature) signature;
Method targetMethod = methodSignature.getMethod();
DistributedLockTrait redisLockTrait = targetMethod.getDeclaredAnnotation(DistributedLockTrait.class);
log.info("redis lock: lockPath = {}, wait = {} ,leaseMs = {}", redisLockTrait.path(), redisLockTrait.waitTimeOut(), redisLockTrait.leaseTimeOut());
String path = StringUtils.isBlank(redisLockTrait.path()) ? (targetMethod.getDeclaringClass().getSimpleName() + "::" + methodSignature.getMethod().getName()) : redisLockTrait.path();
String suffix = "";
Object[] parameters = pjp.getArgs();
/**
* 获取锁的后缀值
*/
for (Object parameter : parameters) {
if (null == parameter) {
continue;
}
if (null != parameter.getClass().getAnnotationsByType(Param.class)) {
/** 一个方法多个参数 获取只有注解 'KEYSUFFIX 的参数*/
Annotation[][] annotations = targetMethod.getParameterAnnotations();
for (Annotation[] annotationi : annotations) {
/** 一个参数多个注解 'KEYSUFFIX 的参数 */
for (Annotation annotation : annotationi) {
if (annotation instanceof Param && ((Param) annotation).value().equals(DistributedLockTrait.PARAMKEY)) {
suffix = "_" + parameter.toString();
break;
}
}
}
}
}
String lockPath = path + suffix;
return lockPath;
}
}
使用
@DistributedLock
public void test() {
}