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() { }