From 7a217140a85f809cf8185f0765c178626e1b4334 Mon Sep 17 00:00:00 2001 From: zhongjiahua <3u6IKJYVS3U#qhr2> Date: Mon, 6 Dec 2021 07:22:23 +0800 Subject: [PATCH 1/2] =?UTF-8?q?=E6=9C=80=E6=96=B0=E5=88=86=E5=B8=83?= =?UTF-8?q?=E5=BC=8F=E9=94=81=E7=9A=84=E6=B5=8B=E8=AF=95=E7=94=A8=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ControllerAcquireLockTimeoutHandler.java | 31 +++++++++ .../CustomerDistributedLockListener.java | 45 +++++++++++++ .../limiter/example/distributed/LockInfo.java | 21 +++++++ .../distributed}/LockTestComponent.java | 22 ++++--- .../distributed}/LockTestController.java | 63 ++++++++++++++----- .../src/main/resources/application.yml | 4 ++ aizuda-redis-lock-example/build.gradle | 6 -- .../redislock/DistributedLimitExtend.java | 25 -------- .../aizuda/redislock/KeyBuilderStrategy.java | 39 ------------ .../RedisLockExampleApplication.java | 18 ------ .../src/main/resources/application.yml | 15 ----- settings.gradle | 1 - 12 files changed, 161 insertions(+), 129 deletions(-) create mode 100644 aizuda-limiter-example/src/main/java/com/aizuda/limiter/example/distributed/ControllerAcquireLockTimeoutHandler.java create mode 100644 aizuda-limiter-example/src/main/java/com/aizuda/limiter/example/distributed/CustomerDistributedLockListener.java create mode 100644 aizuda-limiter-example/src/main/java/com/aizuda/limiter/example/distributed/LockInfo.java rename {aizuda-redis-lock-example/src/main/java/com/aizuda/redislock => aizuda-limiter-example/src/main/java/com/aizuda/limiter/example/distributed}/LockTestComponent.java (52%) rename {aizuda-redis-lock-example/src/main/java/com/aizuda/redislock => aizuda-limiter-example/src/main/java/com/aizuda/limiter/example/distributed}/LockTestController.java (53%) delete mode 100644 aizuda-redis-lock-example/build.gradle delete mode 100644 aizuda-redis-lock-example/src/main/java/com/aizuda/redislock/DistributedLimitExtend.java delete mode 100644 aizuda-redis-lock-example/src/main/java/com/aizuda/redislock/KeyBuilderStrategy.java delete mode 100644 aizuda-redis-lock-example/src/main/java/com/aizuda/redislock/RedisLockExampleApplication.java delete mode 100644 aizuda-redis-lock-example/src/main/resources/application.yml diff --git a/aizuda-limiter-example/src/main/java/com/aizuda/limiter/example/distributed/ControllerAcquireLockTimeoutHandler.java b/aizuda-limiter-example/src/main/java/com/aizuda/limiter/example/distributed/ControllerAcquireLockTimeoutHandler.java new file mode 100644 index 0000000..27ca4d7 --- /dev/null +++ b/aizuda-limiter-example/src/main/java/com/aizuda/limiter/example/distributed/ControllerAcquireLockTimeoutHandler.java @@ -0,0 +1,31 @@ +package com.aizuda.limiter.example.distributed; + +import com.aizuda.limiter.extend.IAcquireLockTimeoutHandler; +import com.aizuda.limiter.metadata.MethodMetadata; +import org.springframework.core.annotation.AnnotatedElementUtils; +import org.springframework.stereotype.Component; +import org.springframework.web.bind.annotation.RequestMapping; + +import java.util.HashMap; + +/** + * @author zhongjiahua + * @date 2021-12-06 + * @Description: 自定义失败处理策略 + */ +@Component +public class ControllerAcquireLockTimeoutHandler implements IAcquireLockTimeoutHandler { + @Override + public boolean supports(MethodMetadata methodMetadata) { + return AnnotatedElementUtils.hasAnnotation(methodMetadata.getMethod(), RequestMapping.class) + && "com.aizuda.limiter.example.distributed.LockTestController.testFailedHandler".equals(methodMetadata.getClassMethodName()); + } + + @Override + public Object onDistributedLockFailure(MethodMetadata methodMetadata) { + return new HashMap(4) {{ + put("failedMessage", "failed acquired lock"); + }}; + } + +} diff --git a/aizuda-limiter-example/src/main/java/com/aizuda/limiter/example/distributed/CustomerDistributedLockListener.java b/aizuda-limiter-example/src/main/java/com/aizuda/limiter/example/distributed/CustomerDistributedLockListener.java new file mode 100644 index 0000000..1955cb2 --- /dev/null +++ b/aizuda-limiter-example/src/main/java/com/aizuda/limiter/example/distributed/CustomerDistributedLockListener.java @@ -0,0 +1,45 @@ +package com.aizuda.limiter.example.distributed; + +import com.aizuda.limiter.extend.IDistributedLockListener; +import com.aizuda.limiter.metadata.MethodMetadata; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +/** + * @author zhongjiahua + * @date 2021-12-06 + * @Description: + */ +@Component +@Slf4j +public class CustomerDistributedLockListener implements IDistributedLockListener { + private ThreadLocal lockInfoThreadLocal = new ThreadLocal<>(); + + @Override + public boolean supports(MethodMetadata methodMetadata) { + return "com.aizuda.limiter.example.distributed.LockTestComponent.testLockListener".equals(methodMetadata.getClassMethodName()); + } + + @Override + public void beforeDistributedLock(MethodMetadata methodMetadata, String lockKey) { + lockInfoThreadLocal.set(new LockInfo().setLockKey(lockKey)); + } + + @Override + public void afterDistributedLock(MethodMetadata methodMetadata, String lockKey) { + lockInfoThreadLocal.get().setAcquireLockSuccessBool(true); + } + + @Override + public void afterExecute(MethodMetadata methodMetadata, String lockKey, Object result) { + lockInfoThreadLocal.get().setExecuteMethodSuccessBool(true); + } + + @Override + public void distributedLockFinally(MethodMetadata methodMetadata, String lockKey) { + LockInfo lockInfo = lockInfoThreadLocal.get(); + log.info("当前分布式锁 key:【{}】,是否获取锁:【{}】,是否执行实际的逻辑:【{}】", lockInfo.getLockKey(), + lockInfo.isAcquireLockSuccessBool(), lockInfo.isExecuteMethodSuccessBool()); + lockInfoThreadLocal.remove(); + } +} diff --git a/aizuda-limiter-example/src/main/java/com/aizuda/limiter/example/distributed/LockInfo.java b/aizuda-limiter-example/src/main/java/com/aizuda/limiter/example/distributed/LockInfo.java new file mode 100644 index 0000000..72a6d57 --- /dev/null +++ b/aizuda-limiter-example/src/main/java/com/aizuda/limiter/example/distributed/LockInfo.java @@ -0,0 +1,21 @@ +package com.aizuda.limiter.example.distributed; + +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; +import lombok.experimental.Accessors; + +/** + * @author zhongjiahua + * @date 2021-12-06 + * @Description: + */ +@Setter +@Getter +@ToString +@Accessors(chain = true) +public class LockInfo { + private String lockKey; + private boolean acquireLockSuccessBool; + private boolean executeMethodSuccessBool; +} diff --git a/aizuda-redis-lock-example/src/main/java/com/aizuda/redislock/LockTestComponent.java b/aizuda-limiter-example/src/main/java/com/aizuda/limiter/example/distributed/LockTestComponent.java similarity index 52% rename from aizuda-redis-lock-example/src/main/java/com/aizuda/redislock/LockTestComponent.java rename to aizuda-limiter-example/src/main/java/com/aizuda/limiter/example/distributed/LockTestComponent.java index c8844ad..6aaf79d 100644 --- a/aizuda-redis-lock-example/src/main/java/com/aizuda/redislock/LockTestComponent.java +++ b/aizuda-limiter-example/src/main/java/com/aizuda/limiter/example/distributed/LockTestComponent.java @@ -1,9 +1,11 @@ -package com.aizuda.redislock; +package com.aizuda.limiter.example.distributed; -import com.aizuda.redislock.annotation.DistributedLimit; +import com.aizuda.limiter.annotation.DistributedLock; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; +import java.util.concurrent.TimeUnit; + /** * @author zhongjiahua * @date 2021-11-28 @@ -13,15 +15,19 @@ import org.springframework.stereotype.Component; @Component public class LockTestComponent { - @DistributedLimit( + @DistributedLock( // 唯一标示,支持SpEL表达式(可无),'#name!=null?#name:'default'' 为获取当前访问参数 name 内容,如果为空,则默认为 'default' key = "#name!=null?#name:'default'", // 指定时间获取锁,如果在指定时间获取不到,则抛出对应异常,捕获此异常即可 - expire = "5s", - // 提示消息 - message = "此锁暂支持重入" + tryAcquireTimeout = "20s" ) - public void testLock(String name) { - log.info("程序运行到这里,说明此分布式锁是可重入的"); + public void testLockListener(String name) { + log.debug("Thread:{} execute testLockListener method",Thread.currentThread().getId()); + try { + TimeUnit.SECONDS.sleep(10); + } catch (InterruptedException e) { + e.printStackTrace(); + Thread.currentThread().interrupt(); + } } } diff --git a/aizuda-redis-lock-example/src/main/java/com/aizuda/redislock/LockTestController.java b/aizuda-limiter-example/src/main/java/com/aizuda/limiter/example/distributed/LockTestController.java similarity index 53% rename from aizuda-redis-lock-example/src/main/java/com/aizuda/redislock/LockTestController.java rename to aizuda-limiter-example/src/main/java/com/aizuda/limiter/example/distributed/LockTestController.java index e946087..7f4b6e0 100644 --- a/aizuda-redis-lock-example/src/main/java/com/aizuda/redislock/LockTestController.java +++ b/aizuda-limiter-example/src/main/java/com/aizuda/limiter/example/distributed/LockTestController.java @@ -1,7 +1,9 @@ -package com.aizuda.redislock; +package com.aizuda.limiter.example.distributed; -import com.aizuda.redislock.annotation.DistributedLimit; +import com.aizuda.limiter.annotation.DistributedLock; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.ApplicationContext; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @@ -17,33 +19,43 @@ import java.util.concurrent.TimeUnit; */ @RestController @RequiredArgsConstructor +@Slf4j public class LockTestController { private final LockTestComponent lockTestComponent; + private final ApplicationContext applicationContext; + private boolean alreadyReentrant; /** * 测试分布式锁的接口,建议多开几个实例测试、 - * 支持可重复 + * 支持可重如 + * --server.port=8081 * * @param name 参数 * @return map */ - @GetMapping("/lock-test") - @DistributedLimit( + @GetMapping("/lock-reentrant") + @DistributedLock( // 唯一标示,支持SpEL表达式(可无),'#name!=null?#name:'default'' 为获取当前访问参数 name 内容,如果为空,则默认为 'default' key = "#name!=null?#name:'default'", // 指定时间获取锁,如果在指定时间获取不到,则抛出对应异常,捕获此异常即可 - expire = "5s", - // 提示消息 - message = "您操作的太快了" + tryAcquireTimeout = "5s", + acquireTimeoutMessage = "您请求的太快了" ) public Map testLock(String name) { + log.debug("Thread:{} execute first method", Thread.currentThread().getId()); + // 测试可重入 + LockTestController bean = applicationContext.getBean(LockTestController.class); + if (!alreadyReentrant) { + alreadyReentrant = true; + bean.testLock(null); + log.info("运行到这里,说明此锁是可重入的"); + } try { TimeUnit.SECONDS.sleep(20); } catch (InterruptedException e) { e.printStackTrace(); Thread.currentThread().interrupt(); } - lockTestComponent.testLock(name); return new HashMap(4) {{ put("name", Optional.ofNullable(name).orElse("default string")); @@ -51,31 +63,48 @@ public class LockTestController { } /** - * 测试自定义key策略 + * 测试获取分布式锁超时策略 * * @param name 参数 * @return map */ - @GetMapping("/custom-key-lock-test") - @DistributedLimit( + @GetMapping("/failed-handler-test") + @DistributedLock( // 唯一标示,支持SpEL表达式(可无),'#name!=null?#name:'default'' 为获取当前访问参数 name 内容,如果为空,则默认为 'default' key = "#name!=null?#name:'default'", // 指定时间获取锁,如果在指定时间获取不到,则抛出对应异常,捕获此异常即可 - expire = "5s", - // 提示消息 - message = "您操作的太快了" + tryAcquireTimeout = "5s" ) - public Map customKeyLock(String name) { + public Map testFailedHandler(String name) { try { TimeUnit.SECONDS.sleep(20); } catch (InterruptedException e) { e.printStackTrace(); Thread.currentThread().interrupt(); } - lockTestComponent.testLock(name); return new HashMap(4) {{ put("name", Optional.ofNullable(name).orElse("default string")); }}; } + + /** + * 测试监听器 + * + * @param name 参数 + * @return map + */ + @GetMapping("/lock-listener-test") + @DistributedLock( + // 唯一标示,支持SpEL表达式(可无),'#name!=null?#name:'default'' 为获取当前访问参数 name 内容,如果为空,则默认为 'default' + key = "#name!=null?#name:'default'", + // 指定时间获取锁,如果在指定时间获取不到,则抛出对应异常,捕获此异常即可 + tryAcquireTimeout = "5s" + ) + public Map testLockListener(String name) { + lockTestComponent.testLockListener(name); + return new HashMap(4) {{ + put("name", Optional.ofNullable(name).orElse("default string")); + }}; + } } diff --git a/aizuda-limiter-example/src/main/resources/application.yml b/aizuda-limiter-example/src/main/resources/application.yml index d9a49bc..0d67101 100644 --- a/aizuda-limiter-example/src/main/resources/application.yml +++ b/aizuda-limiter-example/src/main/resources/application.yml @@ -10,6 +10,10 @@ spring: min-idle: 0 max-wait: 1000ms shutdown-timeout: 100ms +aizuda: + limiter: + # 开启分布式锁 + enableDistributedLock: true logging: level: diff --git a/aizuda-redis-lock-example/build.gradle b/aizuda-redis-lock-example/build.gradle deleted file mode 100644 index bde3d12..0000000 --- a/aizuda-redis-lock-example/build.gradle +++ /dev/null @@ -1,6 +0,0 @@ -description "分布式锁模块示例" - -dependencies { - implementation("com.aizuda:aizuda-redis-lock:1.0.0") - -} \ No newline at end of file diff --git a/aizuda-redis-lock-example/src/main/java/com/aizuda/redislock/DistributedLimitExtend.java b/aizuda-redis-lock-example/src/main/java/com/aizuda/redislock/DistributedLimitExtend.java deleted file mode 100644 index 9f70922..0000000 --- a/aizuda-redis-lock-example/src/main/java/com/aizuda/redislock/DistributedLimitExtend.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.aizuda.redislock; - -import com.aizuda.redislock.annotation.DistributedLimit; -import com.aizuda.redislock.extend.IDistributedLimitExtend; -import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Component; - -import java.lang.reflect.Method; -import java.util.function.Supplier; - -/** - * @author zhongjiahua - * @date 2021-11-28 - * @Description: 分布式锁扩展接口 - */ -@Component -@Slf4j -public class DistributedLimitExtend implements IDistributedLimitExtend { - @Override - public void beforeDistributedLock(Method method, Supplier args, String classMethodName, DistributedLimit distributedLimit, - String lockKey) { - log.info("在运行分布式锁之前打印信息,当前方法:{},当前锁名称:{}", classMethodName, lockKey); - } - -} diff --git a/aizuda-redis-lock-example/src/main/java/com/aizuda/redislock/KeyBuilderStrategy.java b/aizuda-redis-lock-example/src/main/java/com/aizuda/redislock/KeyBuilderStrategy.java deleted file mode 100644 index bd293f1..0000000 --- a/aizuda-redis-lock-example/src/main/java/com/aizuda/redislock/KeyBuilderStrategy.java +++ /dev/null @@ -1,39 +0,0 @@ -package com.aizuda.redislock; - -import com.aizuda.common.toolkit.RequestUtils; -import com.aizuda.redislock.annotation.DistributedLimit; -import com.aizuda.redislock.strategy.IDistributedKeyBuilderStrategy; -import lombok.extern.slf4j.Slf4j; -import org.springframework.core.annotation.AnnotatedElementUtils; -import org.springframework.stereotype.Component; -import org.springframework.web.bind.annotation.RequestMapping; - -import javax.servlet.http.HttpServletRequest; -import java.lang.reflect.Method; - -/** - * @author zhongjiahua - * @date 2021-11-28 - * @Description: 自定义key生成粗略 - */ -@Component -@Slf4j -public class KeyBuilderStrategy implements IDistributedKeyBuilderStrategy { - - @Override - public boolean support(Method method, String classMethodName, DistributedLimit distributedLimit, String distributedLimitKey) { - // 只对controller访问控制 - return AnnotatedElementUtils.hasAnnotation(method, RequestMapping.class) - && "/custom-key-lock-test".equals(RequestUtils.getRequest().getRequestURI()); - } - - @Override - public String buildKey(Method method, String classMethodName, DistributedLimit distributedLimit, String distributedLimitKey) { - HttpServletRequest request = RequestUtils.getRequest(); - String uri = request.getRequestURI(); - - // 用户唯一标识 - String username = "zhangsan"; - return username + ":" + uri + ":" + distributedLimitKey; - } -} diff --git a/aizuda-redis-lock-example/src/main/java/com/aizuda/redislock/RedisLockExampleApplication.java b/aizuda-redis-lock-example/src/main/java/com/aizuda/redislock/RedisLockExampleApplication.java deleted file mode 100644 index 66d12a8..0000000 --- a/aizuda-redis-lock-example/src/main/java/com/aizuda/redislock/RedisLockExampleApplication.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.aizuda.redislock; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -/** - * 限流模块示例 - * - * @author hubin - * @since 2021-11-21 - */ -@SpringBootApplication -public class RedisLockExampleApplication { - - public static void main(String[] args) { - SpringApplication.run(RedisLockExampleApplication.class, args); - } -} diff --git a/aizuda-redis-lock-example/src/main/resources/application.yml b/aizuda-redis-lock-example/src/main/resources/application.yml deleted file mode 100644 index 7540c93..0000000 --- a/aizuda-redis-lock-example/src/main/resources/application.yml +++ /dev/null @@ -1,15 +0,0 @@ -spring: - redis: - port: 6379 - host: localhost - lettuce: - pool: - max-active: 8 - max-idle: 8 - min-idle: 0 - max-wait: 1000ms - shutdown-timeout: 100ms - -logging: - level: - com.aizuda: debug \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index 135eedb..5257a53 100644 --- a/settings.gradle +++ b/settings.gradle @@ -6,5 +6,4 @@ include 'aizuda-limiter-example' include 'aizuda-security-example' include 'aizuda-robot-example' include 'aizuda-common-examples' -include 'aizuda-redis-lock-example' -- Gitee From 71a533c3db50766f8b44d9bb1107d05f857d8674 Mon Sep 17 00:00:00 2001 From: zhongjiahua <3u6IKJYVS3U#qhr2> Date: Mon, 6 Dec 2021 07:27:52 +0800 Subject: [PATCH 2/2] =?UTF-8?q?=E6=9C=80=E6=96=B0=E5=88=86=E5=B8=83?= =?UTF-8?q?=E5=BC=8F=E9=94=81=E7=9A=84=E6=B5=8B=E8=AF=95=E7=94=A8=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../limiter/example/TestController.java | 27 ------------------- .../src/main/resources/application.yml | 4 --- 2 files changed, 31 deletions(-) diff --git a/aizuda-limiter-example/src/main/java/com/aizuda/limiter/example/TestController.java b/aizuda-limiter-example/src/main/java/com/aizuda/limiter/example/TestController.java index 5dc529e..c86f156 100644 --- a/aizuda-limiter-example/src/main/java/com/aizuda/limiter/example/TestController.java +++ b/aizuda-limiter-example/src/main/java/com/aizuda/limiter/example/TestController.java @@ -1,6 +1,5 @@ package com.aizuda.limiter.example; -import com.aizuda.limiter.annotation.DistributedLock; import com.aizuda.limiter.annotation.RateLimit; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @@ -33,30 +32,4 @@ public class TestController { return "test" + name; } - /** - * 分布式锁 - *

- * 测试多次访问观察浏览器及控制台输出日志 - * - * http://localhost:8080/lock?name=abc - * - */ - @GetMapping("/lock") - @DistributedLock( - // 唯一标示,支持SpEL表达式(可无),#name 为获取当前访问参数 name 内容 - key = "#name", - // 限制间隔时长(可无,默认 3 分钟)例如 5s 五秒,6m 六分钟,7h 七小时,8d 八天 - expire = "100s", - // 策略(可无) ip 为获取当前访问IP地址(内置策略),自定义策略 user 为获取当前用户 - strategy = { "ip", "user" } - ) - public String lock(String name) { - try { - // 堵塞测试分布式锁 - Thread.sleep(10000); - } catch (InterruptedException e) { - e.printStackTrace(); - } - return "lock" + name; - } } diff --git a/aizuda-limiter-example/src/main/resources/application.yml b/aizuda-limiter-example/src/main/resources/application.yml index 5ef6792..9be29ef 100644 --- a/aizuda-limiter-example/src/main/resources/application.yml +++ b/aizuda-limiter-example/src/main/resources/application.yml @@ -10,10 +10,6 @@ spring: min-idle: 0 max-wait: 1000ms shutdown-timeout: 100ms -aizuda: - limiter: - # 开启分布式锁 - enableDistributedLock: true aizuda: limiter: -- Gitee