0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

推荐一种非侵入式幂等性的Java实现

jf_ro2CN3Fa 来源:芋道源码 2022-12-22 10:57 次阅读

  • 幂等性
  • 什么场景下需要用到幂等
  • 幂等的实现原理
  • 幂等的代码实现
    • 幂等的使用

幂等性

今天我们来谈谈什么是幂等性

引用百度百科的解析如下:

幂等(idempotent、idempotence)是一个数学与计算机学概念,常见于抽象代数中。

编程中一个幂等操作的特点是其任意多次执行所产生的影响均与一次执行的影响相同。幂等函数,或幂等方法,是指可以使用相同参数重复执行,并能获得相同结果的函数。这些函数不会影响系统状态,也不用担心重复执行会对系统造成改变。例如,“setTrue()”函数就是一个幂等函数,无论多次执行,其结果都是一样的.更复杂的操作幂等保证是利用唯一交易号(流水号)实现。

这解析,确实有点了,大家话看看就行了!!!(●'◡'●)

那对于我们程序员来说,我们关心的更多是下面这些问题:

什么地方,什么场景下需要用到幂等?

幂等,我们需要怎么做,如何实现幂等呢?

基于 Spring Boot + MyBatis Plus + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能

  • 项目地址:https://github.com/YunaiV/ruoyi-vue-pro
  • 视频教程:https://doc.iocoder.cn/video/

什么场景下需要用到幂等

  • 前端表单重复提交问题
  • 用户订单支付问题
  • 银行业务办理取号问题
  • 用户恶意进行调接口问题
  • 接口超时重复提交问题
  • MQ消息进行重复消费
  • ...

当然了,还有很多场景会用到幂等,这里咱们就不一一列举出来了。

那我们要如何设计一个幂等功能呢,而且还是代码非侵入式

代码非侵入式的意思,就是,我们的业务逻辑代码,不需要处理幂等校验的逻辑。

业务功能不处理?那交给谁处理呢?别着急,听哥们一一道来。^_^

这里,要实现代码非侵入式的幂等校验,我们就要使用到切面编程了(@Aspect

基于 Spring Cloud Alibaba + Gateway + Nacos + RocketMQ + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能

  • 项目地址:https://github.com/YunaiV/yudao-cloud
  • 视频教程:https://doc.iocoder.cn/video/

幂等的实现原理

在系统中一些接口需要增加幂等处理,幂等的概念是一个业务请求只能执行一次。类似银行业务办理,首先需要取一个号,然后用户使用这个号去柜台办理业务。这个号只能使用一次,如果过期或者已办理这个号就无效了。

我们的幂等也是使用这种原理。

  • 1.首先客户端调用通过我们的系统获取一个号,我们称之为幂等号,这个号已经存在我们的系统中。
  • 2.客户端使用这个号,调用我们的接口。
  • 3.我们系统判断这个号在我们的系统中已经存在,如果存在则允许业务办理,如果不存在,则表示这是一个非法的号,我们直接抛出异常。
  • 4.当业务处理完成,我们会将这个号从我们的系统中删除掉。

好了,这实现步骤,也是十分清晰了呀!!!^_^

那么我们下面就来看代码如何实现了

幂等的代码实现

  • 定义一个幂等处理接口
publicinterfaceIdempotence{
/**
*检查是否存在幂等号
*@paramidempotenceId幂等号
*@return是否存在
*/
booleancheck(StringidempotenceId);

/**
*记录幂等号
*@paramidempotenceId幂等号
*/
voidrecord(StringidempotenceId);

/**
*记录幂等号
*@paramidempotenceId幂等号
*@paramtime过期时间
*/
voidrecord(StringidempotenceId,Integertime);

/**
*删除幂等号
*@paramidempotenceId幂等号
*/
voiddelete(StringidempotenceId);

}
  • 定义一个幂等处理接口实现类
@Component
publicclassRedisIdempotenceimplementsIdempotence{
@Autowired
privateRedisRepositoryredisRepository;

@Override
publicbooleancheck(StringidempotenceId){
returnredisRepository.exists(idempotenceId);
}

@Override
publicvoidrecord(StringidempotenceId){
redisRepository.set(idempotenceId,"1");
}

@Override
publicvoidrecord(StringidempotenceId,Integertime){
redisRepository.setExpire(idempotenceId,"1",time);
}

@Override
publicvoiddelete(StringidempotenceId){
redisRepository.del(idempotenceId);
}
}

这个实现类,咱们就用redis存储这个幂等号 实现4个方法:

检查是否存在幂等号

记录幂等号

记录幂等号(带过期时间)

删除幂等号

  • 幂等工具类
@Component
publicclassIdempotenceUtil{
@Autowired
privateRedisRepositoryredisRepository;
/**
*生成幂等号
*@return
*/
publicStringgenerateId(){
Stringuuid=UUID.randomUUID().toString();
StringuId=Base64Util.encode(uuid).toLowerCase();
redisRepository.setExpire(uId,"1",1800);
returnuId;
}

/**
*从Header里面获取幂等号
*@return
*/
publicStringgetHeaderIdempotenceId(){
ServletRequestAttributesattributes=(ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
HttpServletRequestrequest=attributes.getRequest();
StringidempotenceId=request.getHeader("idempotenceId");
returnidempotenceId;
}
}

这个工具类,提供两个方法。

1.生成一个幂等号,咱们就用uuid

2.从Header里面获取幂等号

  • 定义一个注解
/**
*接口增加幂等性
*/
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public@interfaceIdempotenceRequired{

}
  • 切面
@Aspect
@Slf4j
@Component
publicclassIdempotenceSupportAdvice{
@Autowired
privateIdempotenceidempotence;
@Autowired
IdempotenceUtilidempotenceUtil;

/**
*拦截有@IdempotenceRequired注解的方法。
*/
@Pointcut("@annotation(xxx.xxx.IdempotenceRequired)")
publicvoididempotenceMethod(){}

@AfterThrowing(value="idempotenceMethod()()",throwing="e")
publicvoidafterThrowing(Throwablee){
if(!(einstanceofIdempotencyException)){
//从HTTPheader中获取幂等号idempotenceId
StringidempotenceId=idempotenceUtil.getHeaderIdempotenceId();
idempotence.record(idempotenceId,1800);
}
}

@Around(value="idempotenceMethod()")
publicObjectaround(ProceedingJoinPointjoinPoint)throwsThrowable{
//从HTTPheader中获取幂等号idempotenceId
StringidempotenceId=idempotenceUtil.getHeaderIdempotenceId();
if(StringUtils.isEmpty(idempotenceId)){
//不存在幂等号则不进行额外操作
returnjoinPoint.proceed();
}
//前置操作幂等号是否存在
booleanexisted=idempotence.check(idempotenceId);
if(!existed){
thrownewIdempotencyException("{success:false,message:"操作重复,请重新输入幂等号重试!",data:-2}");
}
//删除幂等号
idempotence.delete(idempotenceId);
Objectresult=joinPoint.proceed();

returnresult;
}
}
  • 定义个controller
@RequestMapping("/idempotence")
publicclassIdempotenceController{
/**
*生成幂等号
*@return
*/
@GetMapping("/generateId")
publicJsonResultgenerateId(){
IdempotenceUtilidempotenceUtil=SpringUtil.getBean(IdempotenceUtil.class);
StringuId=idempotenceUtil.generateId();
returnJsonResult.success("成功生成!").setData(uId);
}
}

好了,实现的代码,就是这些了,理解起来也是比较简单,没有过多复杂的逻辑。

接下来,就是如何使用的问题了,

这个使用,也是十分的简单啦!!!

幂等的使用

「服务端:」

不是所有的方法都需要切面拦截 ,只有 IdempotenceRequired 注解的方法才会被拦截。

例如下面接口:

@IdempotenceRequired
@PostMapping("/getUsers")
publicJsonResultgetUsers(){

//执行正常业务逻辑
...
}

在开发幂等接口时,只需要在方法上简单增加一个 IdempotenceRequired 注解即可。

这基本上就是代码非侵入式了呀!!!

「客户端:」

服务端处理好后,在客户端访问接口的时候需要执行以下步骤:

  • 需要先获取幂等号
  • 然后将幂等号添加到请求头中

  • 1.获取幂等号http://服务地址/idempotence/generateIdhttp://xn--zfry9hnb732h/idempotence/generateId
3d585d26-8135-11ed-8abf-dac502259ad0.jpg获取幂等号
  • 2.请求调用

往header中添加幂等号

3d7cbdf6-8135-11ed-8abf-dac502259ad0.jpg往header中添加幂等号

好了,到这里幂等的实现,就已经完成了!!!^_^

那我们就可以愉快的编写代码了!!!^_^


审核编辑 :李倩


声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • JAVA
    +关注

    关注

    19

    文章

    2945

    浏览量

    104173
  • 编程
    +关注

    关注

    88

    文章

    3527

    浏览量

    93312
  • 代码
    +关注

    关注

    30

    文章

    4674

    浏览量

    67820

原文标题:推荐一种非侵入式幂等性的Java实现

文章出处:【微信号:芋道源码,微信公众号:芋道源码】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    接触测量传感器有哪些特点

    接触测量传感器是一种利用电磁波、声波、光学接触方式进行测量的传感器。它具有以下特点: 高精度:
    的头像 发表于 08-19 10:07 233次阅读

    华纳云:java web和java有什么区别java web和java有什么区别

    的平台,Java可以用于开发桌面应用程序、移动应用程序、企业级应用程序。 – Java Web是Java语言在Web开发领域的应用,它使用Java
    的头像 发表于 07-16 13:35 371次阅读
    华纳云:<b class='flag-5'>java</b> web和<b class='flag-5'>java</b>有什么区别<b class='flag-5'>java</b> web和<b class='flag-5'>java</b>有什么区别

    接触温度传感器的定义、工作原理、类型、特点、应用和发展趋势

    、类型、特点、应用和发展趋势。 接触温度传感器的定义 接触温度传感器是一种利用物体发
    的头像 发表于 06-19 14:34 1377次阅读

    基于压电陶瓷传感器的智能枕头侵入生命体征监测

    生命体征的智能设备存在高复杂、高成本、侵入或低准确的缺点。因此,迫切需要开发一种简化、无干扰、舒适、低成本的睡眠实时监测系统。在本研究
    发表于 06-12 15:20

    高光谱成像系统:植物表型研究中的侵入成像技术

    植物表型研究与高光谱技术之间存在密切的关联。高光谱技术是一种通过获取植物在各个波段上的反射、辐射或发射数据,从而对植物的生理状态、化学成分、生长情况以及环境适应进行破坏
    的头像 发表于 04-29 10:38 314次阅读
    高光谱成像系统:植物表型研究中的<b class='flag-5'>非</b><b class='flag-5'>侵入</b><b class='flag-5'>性</b>成像技术

    一种基于物联网(IoT)的可穿戴血糖监测(iGM)系统

    定期监测血糖水平对于糖尿病的管理和制定适当的治疗方案来说至关重要。传统的血糖(BG)检测需要刺破手指,是一种侵入技术。如指尖采血检测侵入
    的头像 发表于 03-26 09:21 1497次阅读
    <b class='flag-5'>一种</b>基于物联网(IoT)的可穿戴血糖监测(iGM)系统

    探索LabVIEW编程接口原理与实践

    原来是数学上的概念,在编程领域可以理解为:多次请求某个资源或执行某个操作时应该具有唯一性
    的头像 发表于 02-29 10:24 503次阅读
    探索LabVIEW编程接口<b class='flag-5'>幂</b><b class='flag-5'>等</b><b class='flag-5'>性</b>原理与实践

    为什么要实现校验 如何实现接口的校验

    前端重复提交表单:在填写些表格时候,用户填写完成提交,很多时候会因网络波动没有及时对用户做出提交成功响应,致使用户认为没有成功提交,然后直点提交按钮,这时就会发生重复提交表单请求。
    的头像 发表于 02-20 14:14 1030次阅读

    脑机接口产业进入下阶段,侵入侵入路线均迎来突破

    电子发烧友网报道(文/周凯扬)随着脑机接口迎来产业发展期,侵入侵入脑机接口均迎来了产业化落地,并朝着临产使用迈进了
    的头像 发表于 12-22 00:25 1862次阅读
    脑机接口产业进入下<b class='flag-5'>一</b>阶段,<b class='flag-5'>非</b><b class='flag-5'>侵入</b><b class='flag-5'>式</b>与<b class='flag-5'>侵入</b><b class='flag-5'>式</b>路线均迎来突破

    傲意信息:侵入 VS 侵入,脑机接口产业化的十字路口

    对于侵入侵入脑机接口技术路线的分析,以及傲意信息在脑机接口上开展的相关研究与成果。
    的头像 发表于 12-21 16:44 5015次阅读
    傲意信息:<b class='flag-5'>侵入</b> VS <b class='flag-5'>非</b><b class='flag-5'>侵入</b>,脑机接口产业化的十字路口

    基于汗液的侵入血糖监测公司Persperion获400万美元种子轮投资

    据麦姆斯咨询报道,从美国加州大学圣地亚哥分校(University of California San Diego)雅各布工程学院开发的技术中独立出来的初创公司Persperion Diagnostics获得了400万美元种子轮投资,这笔资金将用于其基于汗液的侵入
    的头像 发表于 12-04 09:49 1387次阅读
    基于汗液的<b class='flag-5'>非</b><b class='flag-5'>侵入</b><b class='flag-5'>式</b>血糖监测公司Persperion获400万美元种子轮投资

    一种基于聚合物的化学电阻传感器使患者检测更容易

    呼吸分析是一种用于医学诊断的侵入(无创)检测工具。然而,目前的呼吸分析仪价格昂贵、耗时,并且需要进行样本气体分离。 据麦姆斯咨询报道,近日,澳大利亚悉尼大学(The Univers
    的头像 发表于 11-08 09:03 333次阅读
    <b class='flag-5'>一种</b>基于聚合物的化学电阻<b class='flag-5'>式</b>传感器使患者检测更容易

    一种多音圈全数字扬声器的设计与实现

    电子发烧友网站提供《一种多音圈全数字扬声器的设计与实现.pdf》资料免费下载
    发表于 11-07 14:45 0次下载
    <b class='flag-5'>一种</b>多音圈<b class='flag-5'>式</b>全数字扬声器的设计与<b class='flag-5'>实现</b>

    请求的些定义和分析

    , HEAD, OPTIONS, PUT or DELETE). ” 什么意思呢?默认情况下,只有当出现网络问题,是“请求”的 5xx 状态码的情况下,才会发起重试,而这里面并不包含 POST 请求。 我就好奇了,这
    的头像 发表于 10-17 10:50 649次阅读

    基于接口解决方案

    接口是指无论调用接口的次数是次还是多次,对于同资源的操作都只会产生次结果。换句话说,
    的头像 发表于 09-30 16:27 373次阅读
    基于接口<b class='flag-5'>幂</b><b class='flag-5'>等</b><b class='flag-5'>性</b>解决方案