From 86fc5e27f269679fd13b9a500757b094bc80004e Mon Sep 17 00:00:00 2001
From: "Yangkai.Shen" <237497819@qq.com>
Date: Fri, 2 Sep 2022 22:14:00 +0800
Subject: [PATCH] =?UTF-8?q?:sparkles:=20=E5=AE=9E=E7=8E=B0=E5=88=86?=
=?UTF-8?q?=E5=B8=83=E5=BC=8F=E9=94=81=E6=8E=A5=E5=8F=A3=E3=80=81AOP?=
=?UTF-8?q?=E6=8B=A6=E6=88=AA=E3=80=81=E8=87=AA=E5=8A=A8=E8=A3=85=E9=85=8D?=
=?UTF-8?q?=E6=A8=A1=E5=9D=97=EF=BC=8C=E9=BB=98=E8=AE=A4=E4=B8=BA=E8=99=9A?=
=?UTF-8?q?=E6=8B=9F=E5=8A=A0=E9=94=81=EF=BC=8C=E5=85=B7=E4=BD=93=E5=AE=9E?=
=?UTF-8?q?=E7=8E=B0=E5=8F=82=E8=80=83=E5=85=B6=E4=BB=96=E6=A8=A1=E5=9D=97?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../demo-distributed-lock-api/pom.xml | 30 ++++++++++
.../distributed/lock/annotation/DLock.java | 28 +++++++++
.../lock/aop/DistributedLockAspect.java | 68 ++++++++++++++++++++++
.../distributed/lock/api/DistributedLock.java | 44 ++++++++++++++
.../lock/api/DistributedLockService.java | 27 +++++++++
.../xkcoding/distributed/lock/api/LockClient.java | 23 ++++++++
.../lock/api/impl/DistributedLockServiceImpl.java | 47 +++++++++++++++
.../lock/api/impl/DummyDistributedLock.java | 41 +++++++++++++
.../lock/api/impl/DummyDistributedLockClient.java | 29 +++++++++
.../DistributedLockConfiguration.java | 31 ++++++++++
.../distributed/lock/mapper/StockMapper.java | 15 +++++
.../com/xkcoding/distributed/lock/model/Stock.java | 29 +++++++++
.../distributed/lock/service/StockService.java | 58 ++++++++++++++++++
.../distributed/lock/task/InitStockTask.java | 31 ++++++++++
.../src/main/resources/META-INF/spring.factories | 2 +
15 files changed, 503 insertions(+)
create mode 100644 demo-distributed-lock/demo-distributed-lock-api/src/main/java/com/xkcoding/distributed/lock/annotation/DLock.java
create mode 100644 demo-distributed-lock/demo-distributed-lock-api/src/main/java/com/xkcoding/distributed/lock/aop/DistributedLockAspect.java
create mode 100644 demo-distributed-lock/demo-distributed-lock-api/src/main/java/com/xkcoding/distributed/lock/api/DistributedLock.java
create mode 100644 demo-distributed-lock/demo-distributed-lock-api/src/main/java/com/xkcoding/distributed/lock/api/DistributedLockService.java
create mode 100644 demo-distributed-lock/demo-distributed-lock-api/src/main/java/com/xkcoding/distributed/lock/api/LockClient.java
create mode 100644 demo-distributed-lock/demo-distributed-lock-api/src/main/java/com/xkcoding/distributed/lock/api/impl/DistributedLockServiceImpl.java
create mode 100644 demo-distributed-lock/demo-distributed-lock-api/src/main/java/com/xkcoding/distributed/lock/api/impl/DummyDistributedLock.java
create mode 100644 demo-distributed-lock/demo-distributed-lock-api/src/main/java/com/xkcoding/distributed/lock/api/impl/DummyDistributedLockClient.java
create mode 100644 demo-distributed-lock/demo-distributed-lock-api/src/main/java/com/xkcoding/distributed/lock/autoconfigure/DistributedLockConfiguration.java
create mode 100644 demo-distributed-lock/demo-distributed-lock-api/src/main/java/com/xkcoding/distributed/lock/mapper/StockMapper.java
create mode 100644 demo-distributed-lock/demo-distributed-lock-api/src/main/java/com/xkcoding/distributed/lock/model/Stock.java
create mode 100644 demo-distributed-lock/demo-distributed-lock-api/src/main/java/com/xkcoding/distributed/lock/service/StockService.java
create mode 100644 demo-distributed-lock/demo-distributed-lock-api/src/main/java/com/xkcoding/distributed/lock/task/InitStockTask.java
create mode 100644 demo-distributed-lock/demo-distributed-lock-api/src/main/resources/META-INF/spring.factories
diff --git a/demo-distributed-lock/demo-distributed-lock-api/pom.xml b/demo-distributed-lock/demo-distributed-lock-api/pom.xml
index 7ff9bb3..a65623b 100644
--- a/demo-distributed-lock/demo-distributed-lock-api/pom.xml
+++ b/demo-distributed-lock/demo-distributed-lock-api/pom.xml
@@ -14,6 +14,36 @@
+ * 分布式锁注解 + *
+ * + * @author yangkai.shen + * @date 2022-09-02 15:47 + */ +public @interface DLock { + /** + * @return 锁的标识,支持 spel 表达式 + */ + String lockKey() default "lock"; + + /** + * @return 锁的时间 + */ + long lockTime() default 3000; + + /** + * @return 锁的时间单位 + */ + TimeUnit timeUnit() default TimeUnit.MILLISECONDS; +} diff --git a/demo-distributed-lock/demo-distributed-lock-api/src/main/java/com/xkcoding/distributed/lock/aop/DistributedLockAspect.java b/demo-distributed-lock/demo-distributed-lock-api/src/main/java/com/xkcoding/distributed/lock/aop/DistributedLockAspect.java new file mode 100644 index 0000000..88af59f --- /dev/null +++ b/demo-distributed-lock/demo-distributed-lock-api/src/main/java/com/xkcoding/distributed/lock/aop/DistributedLockAspect.java @@ -0,0 +1,68 @@ +package com.xkcoding.distributed.lock.aop; + +import com.xkcoding.distributed.lock.annotation.DLock; +import com.xkcoding.distributed.lock.api.DistributedLockService; +import lombok.RequiredArgsConstructor; +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.LocalVariableTableParameterNameDiscoverer; +import org.springframework.expression.ExpressionParser; +import org.springframework.expression.spel.SpelEvaluationException; +import org.springframework.expression.spel.standard.SpelExpressionParser; +import org.springframework.expression.spel.support.StandardEvaluationContext; + +import java.lang.reflect.Method; +import java.util.concurrent.TimeUnit; + +/** + *+ * 分布式锁切面 + *
+ * + * @author yangkai.shen + * @date 2022-09-02 21:02 + */ +@Aspect +@RequiredArgsConstructor +public class DistributedLockAspect { + private final DistributedLockService distributedLockService; + + @Around("@annotation(lock)") + public Object around(ProceedingJoinPoint pjp, DLock lock) throws Throwable { + Method method = ((MethodSignature) pjp.getSignature()).getMethod(); + Object[] args = pjp.getArgs(); + String lockKey = lock.lockKey(); + lockKey = parseExpression(lockKey, method, args); + + long timeout = lock.lockTime(); + TimeUnit timeUnit = lock.timeUnit(); + return distributedLockService.lock(lockKey, timeout, timeUnit, () -> { + try { + return pjp.proceed(); + } catch (Throwable e) { + throw new RuntimeException(e); + } + }); + } + + /** + * 解析 spel 表达式 + */ + private String parseExpression(String expression, Method method, Object[] args) { + LocalVariableTableParameterNameDiscoverer nameDiscoverer = new LocalVariableTableParameterNameDiscoverer(); + String[] params = nameDiscoverer.getParameterNames(method); + + ExpressionParser parser = new SpelExpressionParser(); + StandardEvaluationContext context = new StandardEvaluationContext(); + for (int i = 0; i < params.length; i++) { + context.setVariable(params[i], args[i]); + } + try { + return parser.parseExpression(expression).getValue(context, String.class); + } catch (SpelEvaluationException e) { + throw new RuntimeException("spel 表达式解析错误", e); + } + } +} diff --git a/demo-distributed-lock/demo-distributed-lock-api/src/main/java/com/xkcoding/distributed/lock/api/DistributedLock.java b/demo-distributed-lock/demo-distributed-lock-api/src/main/java/com/xkcoding/distributed/lock/api/DistributedLock.java new file mode 100644 index 0000000..187598d --- /dev/null +++ b/demo-distributed-lock/demo-distributed-lock-api/src/main/java/com/xkcoding/distributed/lock/api/DistributedLock.java @@ -0,0 +1,44 @@ +package com.xkcoding.distributed.lock.api; + +import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.Lock; + +/** + *+ * 分布式锁接口 + *
+ * + * @author yangkai.shen + * @date 2022-09-02 21:30 + */ +public abstract class DistributedLock implements Lock { + /** + * 锁的标识 + */ + private final String lockKey; + /** + * 锁的时间 + */ + private final long lockTime; + /** + * 锁的时间单位 + */ + private final TimeUnit timeUnit; + + protected DistributedLock(String lockKey, long lockTime, TimeUnit timeUnit) { + this.lockKey = lockKey; + this.lockTime = lockTime; + this.timeUnit = timeUnit; + } + + @Override + public void lockInterruptibly() throws InterruptedException { + throw new UnsupportedOperationException("DistributedLock`s lockInterruptibly method is unsupported"); + } + + @Override + public Condition newCondition() { + throw new UnsupportedOperationException("DistributedLock`s newCondition method is unsupported"); + } +} diff --git a/demo-distributed-lock/demo-distributed-lock-api/src/main/java/com/xkcoding/distributed/lock/api/DistributedLockService.java b/demo-distributed-lock/demo-distributed-lock-api/src/main/java/com/xkcoding/distributed/lock/api/DistributedLockService.java new file mode 100644 index 0000000..7b8c432 --- /dev/null +++ b/demo-distributed-lock/demo-distributed-lock-api/src/main/java/com/xkcoding/distributed/lock/api/DistributedLockService.java @@ -0,0 +1,27 @@ +package com.xkcoding.distributed.lock.api; + +import java.util.concurrent.TimeUnit; +import java.util.function.Supplier; + +/** + *+ * 分布式锁实现 + *
+ * + * @author yangkai.shen + * @date 2022-09-02 21:11 + */ +public interface DistributedLockService { + + /** + * 锁 + * + * @param lockKey 锁的标识 + * @param lockTime 锁的时间 + * @param timeUnit 锁的时间单位 + * @param execute 执行逻辑 + * @param+ * 锁客户端 + *
+ * + * @author yangkai.shen + * @date 2022-09-02 21:48 + */ +public interface LockClient { + /** + * 获取一把锁 + * + * @param lockKey 锁的标识 + * @param lockTime 锁的时间 + * @param timeUnit 锁的时间单位 + * @return 锁 + */ + DistributedLock getLock(String lockKey, long lockTime, TimeUnit timeUnit); +} diff --git a/demo-distributed-lock/demo-distributed-lock-api/src/main/java/com/xkcoding/distributed/lock/api/impl/DistributedLockServiceImpl.java b/demo-distributed-lock/demo-distributed-lock-api/src/main/java/com/xkcoding/distributed/lock/api/impl/DistributedLockServiceImpl.java new file mode 100644 index 0000000..8a54723 --- /dev/null +++ b/demo-distributed-lock/demo-distributed-lock-api/src/main/java/com/xkcoding/distributed/lock/api/impl/DistributedLockServiceImpl.java @@ -0,0 +1,47 @@ +package com.xkcoding.distributed.lock.api.impl; + +import com.xkcoding.distributed.lock.api.DistributedLock; +import com.xkcoding.distributed.lock.api.DistributedLockService; +import com.xkcoding.distributed.lock.api.LockClient; +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +import java.util.concurrent.TimeUnit; +import java.util.function.Supplier; + +/** + *+ * 分布式锁实现 + *
+ * + * @author yangkai.shen + * @date 2022-09-02 21:41 + */ +@Slf4j +@AllArgsConstructor +public class DistributedLockServiceImpl implements DistributedLockService { + private final LockClient lockClient; + + /** + * 锁 + * + * @param lockKey 锁 + * @param timeout 超时时间 + * @param timeUnit 超时单位 + * @param execute 执行逻辑 + * @return 返回值 + */ + @Override + public+ * 无锁实现 + *
+ * + * @author yangkai.shen + * @date 2022-09-02 21:32 + */ +public class DummyDistributedLock extends DistributedLock { + + protected DummyDistributedLock(String lockKey, long lockTime, TimeUnit timeUnit) { + super(lockKey, lockTime, timeUnit); + } + + @Override + public void lock() { + // Do nothing. + } + + @Override + public boolean tryLock() { + return true; + } + + @Override + public boolean tryLock(long time, @NotNull TimeUnit unit) throws InterruptedException { + return true; + } + + @Override + public void unlock() { + + } +} diff --git a/demo-distributed-lock/demo-distributed-lock-api/src/main/java/com/xkcoding/distributed/lock/api/impl/DummyDistributedLockClient.java b/demo-distributed-lock/demo-distributed-lock-api/src/main/java/com/xkcoding/distributed/lock/api/impl/DummyDistributedLockClient.java new file mode 100644 index 0000000..30abc11 --- /dev/null +++ b/demo-distributed-lock/demo-distributed-lock-api/src/main/java/com/xkcoding/distributed/lock/api/impl/DummyDistributedLockClient.java @@ -0,0 +1,29 @@ +package com.xkcoding.distributed.lock.api.impl; + +import com.xkcoding.distributed.lock.api.DistributedLock; +import com.xkcoding.distributed.lock.api.LockClient; + +import java.util.concurrent.TimeUnit; + +/** + *+ * 获取一把虚拟锁 + *
+ * + * @author yangkai.shen + * @date 2022-09-02 21:53 + */ +public class DummyDistributedLockClient implements LockClient { + /** + * 获取一把锁 + * + * @param lockKey 锁的标识 + * @param lockTime 锁的时间 + * @param timeUnit 锁的时间单位 + * @return 锁 + */ + @Override + public DistributedLock getLock(String lockKey, long lockTime, TimeUnit timeUnit) { + return new DummyDistributedLock(lockKey, lockTime, timeUnit); + } +} diff --git a/demo-distributed-lock/demo-distributed-lock-api/src/main/java/com/xkcoding/distributed/lock/autoconfigure/DistributedLockConfiguration.java b/demo-distributed-lock/demo-distributed-lock-api/src/main/java/com/xkcoding/distributed/lock/autoconfigure/DistributedLockConfiguration.java new file mode 100644 index 0000000..78a99dd --- /dev/null +++ b/demo-distributed-lock/demo-distributed-lock-api/src/main/java/com/xkcoding/distributed/lock/autoconfigure/DistributedLockConfiguration.java @@ -0,0 +1,31 @@ +package com.xkcoding.distributed.lock.autoconfigure; + +import com.xkcoding.distributed.lock.api.DistributedLockService; +import com.xkcoding.distributed.lock.api.LockClient; +import com.xkcoding.distributed.lock.api.impl.DistributedLockServiceImpl; +import com.xkcoding.distributed.lock.api.impl.DummyDistributedLockClient; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + *+ * 自动装配类 + *
+ * + * @author yangkai.shen + * @date 2022-09-02 21:57 + */ +@Configuration(proxyBeanMethods = false) +public class DistributedLockConfiguration { + @Bean + @ConditionalOnMissingBean + public LockClient lockClient() { + return new DummyDistributedLockClient(); + } + + @Bean + public DistributedLockService distributedLockService(LockClient lockClient) { + return new DistributedLockServiceImpl(lockClient); + } +} diff --git a/demo-distributed-lock/demo-distributed-lock-api/src/main/java/com/xkcoding/distributed/lock/mapper/StockMapper.java b/demo-distributed-lock/demo-distributed-lock-api/src/main/java/com/xkcoding/distributed/lock/mapper/StockMapper.java new file mode 100644 index 0000000..e6eee49 --- /dev/null +++ b/demo-distributed-lock/demo-distributed-lock-api/src/main/java/com/xkcoding/distributed/lock/mapper/StockMapper.java @@ -0,0 +1,15 @@ +package com.xkcoding.distributed.lock.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.xkcoding.distributed.lock.model.Stock; +import org.apache.ibatis.annotations.Mapper; + +/** + * 货物 Mapper + * + * @author yangkai.shen + * @date 2022-09-02 14:09 + */ +@Mapper +public interface StockMapper extends BaseMapper+ * 初始化数据 + *
+ * + * @author yangkai.shen + * @date 2022-09-02 15:35 + */ +@Slf4j +@Component +@RequiredArgsConstructor(onConstructor_ = @Autowired) +public class InitStockTask implements ApplicationRunner { + private final StockService stockService; + + @Override + public void run(ApplicationArguments args) throws Exception { + log.info("================================================"); + stockService.resetStock(); + log.info("================================================"); + } +} diff --git a/demo-distributed-lock/demo-distributed-lock-api/src/main/resources/META-INF/spring.factories b/demo-distributed-lock/demo-distributed-lock-api/src/main/resources/META-INF/spring.factories new file mode 100644 index 0000000..ad1e9df --- /dev/null +++ b/demo-distributed-lock/demo-distributed-lock-api/src/main/resources/META-INF/spring.factories @@ -0,0 +1,2 @@ +org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ + com.xkcoding.distributed.lock.autoconfigure.DistributedLockConfiguration