幂等
continew-starter-idempotent 基于 AOP + 注解结合 Redis 实现的分布式幂等模块,通过 @Idempotent 注解一行代码防止接口重复提交。
continew-starter-idempotent 基于 AOP + 注解结合 Redis 实现分布式幂等,在接口方法上添加 @Idempotent 注解即可防止重复提交,支持 SpEL 表达式动态解析幂等 Key。
主要特性:
- 开箱即用:引入依赖后仅需一个注解即可生效
- 支持 SpEL 表达式:可动态解析请求参数作为幂等 Key,如
@Idempotent(key = "#req.username") - 提供默认的幂等名称生成器
DefaultIdempotentNameGenerator,也可自行实现替换
引入依赖
<dependency>
<groupId>top.continew.starter</groupId>
<artifactId>continew-starter-idempotent</artifactId>
</dependency>本模块内部依赖 continew-starter-cache-redisson 进行幂等键的存取(见 pom.xml 第 19-23 行),因此需要可用的 Redis 环境。
配置
配置属性类为 top.continew.starter.idempotent.autoconfigure.IdempotentProperties。
continew-starter:
idempotent:
# 是否启用(默认:true)
enabled: true
# 幂等统一 Key 前缀(默认:Idempotent)
key-prefix: Idempotent| 配置项 | 说明 | 默认值 |
|---|---|---|
continew-starter.idempotent.enabled | 模块开关(自动配置条件,非绑定属性;matchIfMissing = true,不配即启用) | true |
continew-starter.idempotent.key-prefix | 幂等键在 Redis 中的统一前缀 | Idempotent |
enabled 是自动配置类上的 @ConditionalOnProperty 条件,不由 IdempotentProperties 绑定,因此 IDE 配置提示里不会出现这一项。设置它照样生效(关掉整个模块),只是它和下面这类有 getter/setter 的键在机制上不同。
使用
在需要幂等处理的接口方法上添加 top.continew.starter.idempotent.annotation.Idempotent 注解:
@Operation(summary = "创建用户")
@PostMapping
@Idempotent(key = "#req.username")
public R createUser(@Valid @RequestBody UserReq req) {
// 业务逻辑 ...
}在 timeout 时间窗口内,相同幂等键的重复请求会抛出 IdempotentException,默认提示「请勿重复操作」。
@Idempotent 注解属性
源码见 Idempotent.java,各属性及默认值如下:
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
name | String | "" | 幂等名称;留空时由 IdempotentNameGenerator 自动生成 |
key | String | "" | 幂等键,支持 SpEL 表达式,按方法参数动态解析 |
timeout | int | 1000 | 超时时间(时间窗口),窗口内重复请求视为重复提交 |
unit | TimeUnit | TimeUnit.MILLISECONDS | 超时时间单位 |
message | String | "请勿重复操作" | 重复提交时的提示信息 |
幂等键的生成规则
幂等键由 IdempotentAspect.getCacheKey 生成,最终格式为 keyPrefix:name:key,各部分用 : 拼接(空白部分会被忽略):
keyPrefix:即配置项continew-starter.idempotent.key-prefix,默认Idempotent;name:注解name属性;为空时由IdempotentNameGenerator生成。默认实现DefaultIdempotentNameGenerator按「类名:方法名:参数 JSON 的 MD5」生成;key:注解key属性的 SpEL 解析结果,如#req.username;若解析结果为null会抛出IdempotentException("幂等 Key 解析错误")。
注意:目标方法执行抛出异常时,切面会主动删除该幂等键(见 IdempotentAspect.around 第 73-77 行),以便调用方重试;只有执行成功的请求才会在 timeout 窗口内拦截重复提交。
自定义幂等名称生成器
实际业务中,幂等通常需要区分当前用户(如拼接当前用户的 Token、用户 ID)。此时可实现 IdempotentNameGenerator 接口并注册为 Spring Bean,自动配置的默认生成器会被替换(@ConditionalOnMissingBean):
@Configuration
public class GlobalConfiguration {
/**
* 自定义幂等名称生成器
*/
@Bean
public IdempotentNameGenerator idempotentNameGenerator() {
return new MyIdempotentNameGenerator();
}
}public class MyIdempotentNameGenerator implements IdempotentNameGenerator {
@Override
public String generate(Object target, Method method, Object... args) {
// 拼接当前用户标识 + 方法签名,实现按用户隔离的幂等
return LoginHelper.getUserId() + ":" + target.getClass().getSimpleName() + ":" + method.getName();
}
}接口定义(源码见 IdempotentNameGenerator.java):
public interface IdempotentNameGenerator {
/**
* 生成幂等名称
*
* @param target 目标实例
* @param method 目标方法
* @param args 方法参数
* @return 幂等名称
*/
String generate(Object target, Method method, Object... args);
}核心依赖
| 依赖 | 描述 |
|---|---|
top.continew.starter:continew-starter-cache-redisson | 缓存模块,提供幂等键存取(RedisUtils) |
cn.hutool:hutool-crypto | Hutool 加密模块(默认名称生成器用于计算参数摘要) |