业务相关参数-idempotentId
idempotentId 幂等Id生成器,每个重试请求中,其中默认的实现方法为SimpleIdempotentIdGenerate,我们一起来看一下这个方法是如何实现的。
public class SimpleIdempotentIdGenerate implements IdempotentIdGenerate {
@Override
public String idGenerate(IdempotentIdGenerateEntity idempotentIdGenerateEntity) throws Exception {
return SecureUtil.md5(idempotentIdGenerateEntity.toString());
}
}
/**
* 参数列表为IdempotentIdGenerateEntity包含了四个对象, 下面说明每一个下标代表的数据含义
* 场景名称: scene(String)
* 执行器名称: targetClassName(String)
* 参数列表: args(Object[])
* 执行的方法名称: methodName(String)
* scene, targetClassName, args, executorMethod.getName()
*
* @param t 参数列表
* @return idempotentId
* @throws Exception
*/
public interface IdempotentIdGenerate {
String idGenerate(IdempotentIdGenerateEntity idempotentIdGenerateEntity) throws Exception;
}
可以看到,默认实现中我们取scene场景名称,targetClassName执行器名称,args参数列表,methodName执行的方法名称来进行了一个md5运算作为重试任务的幂等Id,由此来保证任务是唯一的,这种实现方式下,对象中的四个参数中有一个变化都会新建一个重试任务。 当然,在一些特殊的业务场景下我们可以重写IdempotentIdGenerate来实现幂等Id的自定义。 接下来我们再来看一个案例。这次我们来模拟一个业务场景,举个例子,一个商品下单的场景,用户购买某个限购的商品,此时用户可以通过手机下单,也可以通过PC下单,此时两个请求的订单号相同,一端下单成功后,另一端不可重复下单。此时假设下单服务发生异常,我们仅需产生一次重试任务即可,无需根据客户端不同发生多次请求。
那么怎么来实现这个场景呢?我们首先来定义一个商品的VO,为了简化表述,我们在其中仅仅放入订单ID和订单来源信息两个字段。
@Data
public class OrderVo {
private String orderId; // 订单ID,用于唯一标识订单的编号
private Integer source; // 订单来源信息,1-手机端下单 2-PC端下单
}
然后我们自定义一个幂等Id生成类
/**
* 使用自定义的幂等Id生成类 OrderIdempotentIdGenerate
*/
@Retryable(scene = "remoteRetryWithIdempotentId",retryStrategy = RetryType.ONLY_REMOTE,
idempotentId = OrderIdempotentIdGenerate.class)
public boolean remoteRetryWithIdempotentId(OrderVo orderVo){
double i = 1 / 0;
return true;
}
在其中我们指定了幂等Id的生成规则为自定义的生成规则,然后我们在代码中继承IdempotentIdGenerate类,给出一个OrderIdempotentIdGenerate类,我们从IdempotentIdContext取出args参数,这个参数代表了我们从接口传入的参数,在这个接口中,我们取出args参数数组中下标为0的参数,转换为OrderVo类型,然后指定幂等Id的生成规则是取出orderId求md5。
public class OrderIdempotentIdGenerate implements IdempotentIdGenerate {
@Override
public String idGenerate(IdempotentIdContext idempotentIdContext) throws Exception {
Object[] args = idempotentIdContext.getArgs();
OrderVo orderVo = (OrderVo) args[0];
return SecureUtil.md5(orderVo.getOrderId());
}
}
接下来我们测试看看效果吧。首先我们给出三个Post请求,其中请求1是原始请求,请求2中orderId和请求1一致仅仅修改source,请求3中source保持不变,仅仅修改orderId。
依次执行三个请求我们可以观察到,请求1和请求2执行之后仅有一条数据生成,幂等Id没有变化,也没有生成新的重试任务;而执行请求3之后生成了一条新的重试任务。