diff --git "a/doc/idemopent/idemopent-\345\271\202\347\255\211-\345\267\245\345\205\267\350\256\276\350\256\241\350\257\264\346\230\216.md" "b/doc/idemopent/idemopent-\345\271\202\347\255\211-\345\267\245\345\205\267\350\256\276\350\256\241\350\257\264\346\230\216.md" new file mode 100644 index 0000000000000000000000000000000000000000..b3281489e8bca45f9e433a789cef591da649a033 --- /dev/null +++ "b/doc/idemopent/idemopent-\345\271\202\347\255\211-\345\267\245\345\205\267\350\256\276\350\256\241\350\257\264\346\230\216.md" @@ -0,0 +1,165 @@ +# 幂等工具设计说明 + +> Author : kongxiang +> +> Date Time : 2023-08-27 + + +## 1. 概述 +希望spring环境中,快速支持接口幂等能力。简单引入,自动配置。通过注解就可以直接使用。 +无需复杂配置 + +功能: +- [ ] 基于spring框架 +- [ ] 直接进入jar,即可直接使用 +- [ ] 通过`@Idempotent`注解一键赋能类或方法幂等性 +- [ ] 支持指定token生成算法 +- [ ] 可支持自定义实现token缓冲存储 +- [ ] + + +## 2. 如何引入 +```xml + + com.kongxiang + kongxiang-spring + {version} + +``` + +## 3. 如何使用 + +### 3.1 设计思路 +![](./idempotent-class.png) + +#### 3.1.1 使用设计 +要求:开发人员通过配置一个注解`@Idempotent`即可使注解的方法调用时,实现幂等性。 + +幂等性方案: +- [x] 防重token令牌 + +设计: +1. 基于环境Spring 框架。所以采用Spring Aop 拦截注解方法和类。自定义 幂等 逻辑,实现幂等要求。 + +2. 梳理流程: client请求【携带token和userid】-> 服务端Aop拦截【配置@Idempotent 】-> 获取注解信息 -> 认证token和userId -> 通过,执行业务逻辑,失败返回错误信息 + +3. 抽象出存储接口`TokenCache`和请求体传输token方式`TokenHolder` + +4. @Idempontent注解在类和方法上的优先级设计:方法上注解配置信息优先于类上注解信息。注意:只是覆盖重复配置。 + +5. TokenCache 存储接口实现,是抽象出的一个接口。支持存储自定义配置方案。该框架:已经实现的方式:1. InMemory 2. Reids + > 根据接入环境的配置。如果已经接入`spring-boot-starter-redis`和连接redis服务成功。那么将会使用`RedisTokenCache`,否则默认使用`InMemoryTokenCache`.如果是redis,可以使用application.yml配置相关属性【为实现】 + +6. 设计请求体提供token接口的目的,是兼容在不同spring环境下,直接调用注解@Idempotent方法时,提供给Aop防重Token处理逻辑校验中去获取token和value的能力。如:在正常spring web环境中,采用的是HttpSerlvetRequest中去获取token和value。而在非spring环境中,也需要自动提供获取token的方式。根据web中底层实现原理。采用ThreadLocal绑定线程的特点,实现aop在内部线程获取token。 + +#### 3.1.2 具体接入 + +#### 3.1.2.1 引入包 + +```xml + + com.kongxiang + kongxiang-spring + {version} + +``` + + + +#### 3.1.2.2 注解方法@Idempotent + +支持 注解类 和注解方法 + +- 注解类:类下面所有的方法被调用时,执行幂等逻辑 +- 注解方法: 该方法被调用时,执行幂等逻辑 + +```java +@Idempotent +public class HelloWorld{ + + public void a(){ + + } + @Idempotent + public void b(){ + + } +} +``` + +#### 3.1.2.3 开发代码 + +- 在普通方法中调用 + + ```java + @Compoment + public class Client { + + /**TODO 这个目前是个具体类,后续需要改造 幂等实现方式接口IdempotentCaseHanlder,该类只是接口的一个实现类而已 */ + @Autowire + private AntiDuplicationTokenHanlder tokenHanlder; + + @Autowire + private HelloWorld helloWorld;// 自己开发的幂等注解服务 + + private Stirng token; + // 用户信息最开始就提供了 + private String userInfo = getUseInfo(); + + // 1. 客户端先获取token + public void requestGetToken(String userInfo){ + this.token = tokenHandler.getToken(userInfo); + } + // 2. 执行幂等函数 + public void execute(){ + requestGetToken(userInfo ); + // 传递参数 + // 不加这行,该线程传递的参数是之前的。userInfo验证不通过。也不会执行业务逻辑 + TokenHolder.setToken(this.token,this.userInfo); + // 执行幂等操作 + helloWorld.b(); + //第二次和之后操作会报错 + helloWorld.b(); + + // ------- + requestGetToken(userInfo+"1"); + TokenHolder.setToken(this.token,this.userInfo); + + helloWorld.b();// 报错 userInfo 验证失败 + TokenHolder.setToken(this.token,this.userInfo+"1"); + helloWorld.b();// 成功 + helloWorld.b();// 报错 userInfo 验证失败 + } + } + ``` + +- 在spring web中接口中使用 + + 1. 实现 getToken接口【必须提供给客户端获取token的接口】 + 2. 在注解使用 + +```java +@RestController +@RequestMapping +// 注解类:类中所有方法都幂等 +@Idempotent +public class Service{ + /**TODO 这个目前是个具体类,后续需要改造 幂等实现方式接口IdempotentCaseHanlder,该类只是接口的一个实现类而已 */ + @Autowire + private AntiDuplicationTokenHanlder tokenHanlder; + // [防重token令牌方案必须提供给客户端,其他自定义方案不定] + @RequestMapping("/getToken") + public String getToken(){ + return tokenHanlder.getToken(); + } + + @RequestMapping("/login") + // 只有该方法幂等 + @Idempotent + public Object login(){ + ... + } + +} +``` + diff --git a/doc/idemopent/idempotent-class.png b/doc/idemopent/idempotent-class.png new file mode 100644 index 0000000000000000000000000000000000000000..1e870b96ede6a7b1b5151ba90047d0e84ff3b0cf Binary files /dev/null and b/doc/idemopent/idempotent-class.png differ