提交 18905356 编写于 作者: 无难事者若执's avatar 无难事者若执

doc : 【幂等】 :编写设计文档

上级 0ea5bb1d
# 幂等工具设计说明
> Author : kongxiang
>
> Date Time : 2023-08-27
## 1. 概述
希望spring环境中,快速支持接口幂等能力。简单引入,自动配置。通过注解就可以直接使用。
无需复杂配置
功能:
- [ ] 基于spring框架
- [ ] 直接进入jar,即可直接使用
- [ ] 通过`@Idempotent`注解一键赋能类或方法幂等性
- [ ] 支持指定token生成算法
- [ ] 可支持自定义实现token缓冲存储
- [ ]
## 2. 如何引入
```xml
<dependency>
<groupId>com.kongxiang</groupId>
<artifactId>kongxiang-spring</artifactId>
<version>{version}</version>
</dependency>
```
## 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
<dependency>
<groupId>com.kongxiang</groupId>
<artifactId>kongxiang-spring</artifactId>
<version>{version}</version>
</dependency>
```
#### 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(){
...
}
}
```
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册