From 3d6cd0dddedafebbad7c581060b9348a7063306f Mon Sep 17 00:00:00 2001 From: zlt2000 Date: Sat, 6 Jun 2020 15:24:27 +0800 Subject: [PATCH] =?UTF-8?q?=E5=88=86=E5=B8=83=E5=BC=8F=E9=94=81=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=E6=B3=A8=E8=A7=A3=E8=B0=83=E7=94=A8=E6=96=B9=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/central/common/lock/Lock.java | 39 +++++++ .../com/central/common/lock/LockAspect.java | 100 ++++++++++++++++++ .../main/resources/META-INF/spring.factories | 3 +- .../redis/lock/RedissonDistributedLock.java | 2 + 4 files changed, 143 insertions(+), 1 deletion(-) create mode 100644 zlt-commons/zlt-common-core/src/main/java/com/central/common/lock/Lock.java create mode 100644 zlt-commons/zlt-common-core/src/main/java/com/central/common/lock/LockAspect.java diff --git a/zlt-commons/zlt-common-core/src/main/java/com/central/common/lock/Lock.java b/zlt-commons/zlt-common-core/src/main/java/com/central/common/lock/Lock.java new file mode 100644 index 0000000..6be1883 --- /dev/null +++ b/zlt-commons/zlt-common-core/src/main/java/com/central/common/lock/Lock.java @@ -0,0 +1,39 @@ +package com.central.common.lock; + +import java.lang.annotation.*; +import java.util.concurrent.TimeUnit; + +/** + * @author zlt + * @date 2020/6/6 + *

+ * Blog: https://zlt2000.gitee.io + * Github: https://github.com/zlt2000 + */ +@Target({ElementType.METHOD, ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface Lock { + /** + * 锁的key + */ + String key(); + /** + * 获取锁的最大尝试时间(单位毫秒) + * 该值大于0则使用 locker.tryLock 方法加锁,否则使用 locker.lock 方法 + */ + long waitTime() default 0; + /** + * 加锁的时间,超过这个时间后锁便自动解锁; + * 如果leaseTime为-1,则保持锁定直到显式解锁 + */ + long leaseTime() default -1; + /** + * 参数的时间单位 + */ + TimeUnit unit() default TimeUnit.SECONDS; + /** + * 是否公平锁 + */ + boolean isFair() default false; +} diff --git a/zlt-commons/zlt-common-core/src/main/java/com/central/common/lock/LockAspect.java b/zlt-commons/zlt-common-core/src/main/java/com/central/common/lock/LockAspect.java new file mode 100644 index 0000000..ec7c764 --- /dev/null +++ b/zlt-commons/zlt-common-core/src/main/java/com/central/common/lock/LockAspect.java @@ -0,0 +1,100 @@ +package com.central.common.lock; + +import cn.hutool.core.util.StrUtil; +import com.central.common.exception.LockException; +import lombok.extern.slf4j.Slf4j; +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.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; + +/** + * 分布式锁切面 + * + * @author zlt + * @date 2020/6/6 + *

+ * Blog: https://zlt2000.gitee.io + * Github: https://github.com/zlt2000 + */ +@Slf4j +@Aspect +public class LockAspect { + private DistributedLock locker; + + public LockAspect(DistributedLock locker) { + this.locker = locker; + } + + /** + * 用于SpEL表达式解析. + */ + private SpelExpressionParser spelExpressionParser = new SpelExpressionParser(); + /** + * 用于获取方法参数定义名字. + */ + private DefaultParameterNameDiscoverer nameDiscoverer = new DefaultParameterNameDiscoverer(); + + @Around("@within(lock) || @annotation(lock)") + public Object aroundLock(ProceedingJoinPoint point, Lock lock) throws Throwable { + Object lockObj = null; + if (lock == null) { + // 获取类上的注解 + lock = point.getTarget().getClass().getDeclaredAnnotation(Lock.class); + } + String lockKey = lock.key(); + if (locker == null) { + throw new LockException("DistributedLock is null"); + } + if (StrUtil.isEmpty(lockKey)) { + throw new LockException("lockKey is null"); + } + + if (lockKey.contains("#")) { + MethodSignature methodSignature = (MethodSignature)point.getSignature(); + //获取方法参数值 + Object[] args = point.getArgs(); + lockKey = getValBySpEL(lockKey, methodSignature, args); + } + try { + //加锁 + if (lock.waitTime() > 0) { + lockObj = locker.tryLock(lockKey, lock.waitTime(), lock.leaseTime(), lock.unit(), lock.isFair()); + } else { + lockObj = locker.lock(lockKey, lock.leaseTime(), lock.unit(), lock.isFair()); + } + + if (lockObj != null) { + return point.proceed(); + } else { + throw new LockException("锁等待超时"); + } + } finally { + locker.unlock(lockObj); + } + } + + /** + * 解析spEL表达式 + */ + private String getValBySpEL(String spEL, MethodSignature methodSignature, Object[] args) { + //获取方法形参名数组 + String[] paramNames = nameDiscoverer.getParameterNames(methodSignature.getMethod()); + if (paramNames != null && paramNames.length > 0) { + Expression expression = spelExpressionParser.parseExpression(spEL); + // spring的表达式上下文对象 + EvaluationContext context = new StandardEvaluationContext(); + // 给上下文赋值 + for(int i = 0; i < args.length; i++) { + context.setVariable(paramNames[i], args[i]); + } + return expression.getValue(context).toString(); + } + return null; + } +} diff --git a/zlt-commons/zlt-common-core/src/main/resources/META-INF/spring.factories b/zlt-commons/zlt-common-core/src/main/resources/META-INF/spring.factories index 247a111..c56b4c9 100644 --- a/zlt-commons/zlt-common-core/src/main/resources/META-INF/spring.factories +++ b/zlt-commons/zlt-common-core/src/main/resources/META-INF/spring.factories @@ -2,4 +2,5 @@ org.springframework.context.ApplicationContextInitializer=\ com.central.common.config.BannerInitializer org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ -com.central.common.feign.fallback.UserServiceFallbackFactory \ No newline at end of file +com.central.common.feign.fallback.UserServiceFallbackFactory,\ +com.central.common.lock.LockAspect \ No newline at end of file diff --git a/zlt-commons/zlt-redis-spring-boot-starter/src/main/java/com/central/common/redis/lock/RedissonDistributedLock.java b/zlt-commons/zlt-redis-spring-boot-starter/src/main/java/com/central/common/redis/lock/RedissonDistributedLock.java index 94b1d98..d090b98 100644 --- a/zlt-commons/zlt-redis-spring-boot-starter/src/main/java/com/central/common/redis/lock/RedissonDistributedLock.java +++ b/zlt-commons/zlt-redis-spring-boot-starter/src/main/java/com/central/common/redis/lock/RedissonDistributedLock.java @@ -7,6 +7,7 @@ import org.redisson.api.RLock; import org.redisson.api.RedissonClient; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import java.util.concurrent.TimeUnit; @@ -21,6 +22,7 @@ import java.util.concurrent.TimeUnit; * Github: https://github.com/zlt2000 */ @ConditionalOnClass(RedissonClient.class) +@ConditionalOnProperty(prefix = "zlt.lock", name = "lockerType", havingValue = "REDIS", matchIfMissing = true) public class RedissonDistributedLock implements DistributedLock { @Autowired private RedissonClient redisson; -- GitLab