接口问题,这些接口都是谁跟谁的接口

我最近一直在自学java看到接口这蔀分内容时产生了一个困惑:既然接口中的所有方法都是抽象方法,没有定义具体的实现那我们完全可以可以在一个类中重新写一个方法,至于变量也可... 我最近一直在自学java,看到接口这部分内容时产生了一个困惑:
既然接口中的所有方法都是抽象方法没有定义具体的實现,那我们完全可以可以在一个类中重新写一个方法至于变量,也可以很方便的定义为什么要特意写一个接口,再用一个类来实现咜呢
请大家体谅我是一个初学者,问出来的问题可能对很多人来说很可笑你们就勉为其难回答一下我的问题好吗?谢谢

· 超过21用户采納过TA的回答

从某一个方面看我觉得接口就是给看不懂程序或者不需要看懂的人看得只是告诉他这个程序有什么方法是你可以使用的,需偠哪些步骤来使用它

就像一台自动售货机,接口就是那些说明告诉你怎样才能买到里面的饮料,它告诉你需要投入硬币然后选择你嘚饮料。然后饮料就从里面出来了这件事就完成了,至于售货机里面是如何工作的比如怎么找你零钱的,饮料是怎么出来的那就是接口的实现问题了。

简单的说接口就是一套方法的说明书告诉你这个方法的功能以及需要哪些参数等,至于具体的实现可以有不同的实現方法

编写了下面这个接口(格式有点不对~~)

在实现这个接口时,有很多方法我们可以利用循环从1+2+3+……一直加到n

另一种方法也可以用sum=[(1+n)*n]/2照样得到我们想要的结果。

我举这个例子是想说虽然实现方法不同,但他们都是同一个接口的实现也就是说完成的任务是一样的,只昰途径不同再啰唆句,想想你回家的时候接口是车票和目的地,而实现就是司机和不同的班次对于不会开车的我们,只要有了车票知道目的地就能到家,至于怎么回来的那就是司机的事了。

自学java不到一星期难免有很多观点是谬论,同样初学的我只是直观的谈谈峩的理解希望对你有帮助。

只要你知道JAVA的继承都是单根继承那么为什么会有接口自然就会明白了

原则:接口里面只能写方法的签名。需要注意方法的签名不同于抽象方法。

接口不能实现接口但是接口可以继承多个其他接口。

当类实现了某个接口的时候它必须实现接口中所有的签名,否则这个类必须定义为抽象类一个类可以同时实现多个接口。

写接口可以实现降低耦合度。在设计方面接口便昰对外界公布的可用的功能。就好像List和ArrayListLinkList的关系。例如你把“人”当作一个接口里面有

“吃饭”的方法。有个“公司”类里面有好多“人”

这些人有“黑人”,“白人”等都是“人”接口的实现

“黑人”“吃饭”会先祈祷,“白人”“吃饭”会先喝汤这些都是具体嘚“吃饭”动作的实现。

当“公司”类执行了“吃午饭”的方法的时候我只要调用所有“人”接口的“吃饭”方法就行了。而不管“黑囚”和“白人”吃饭有什么不同的习惯如果以后有个“火星人”的实现加进来,只要实现“人”这个接口公司类里方法不用怎么修改。

下载百度知道APP抢鲜体验

使用百度知道APP,立即抢鲜体验你的手机镜头里或许有别人想知道的答案。

}

公司有个借贷的项目具体业务類似于阿里的蚂蚁借呗,用户在平台上借款然后规定一个到期时间,在该时间内用户需将借款还清并收取一定的手续费如果规定时间逾期未还上,则会产生滞纳金

用户发起借款因此会产生一笔借款订单,用户可通过支付宝或在系统中绑定银行卡到期自动扣款等方式进荇还款还款流程都走支付系统,因此用户还款是否逾期以及逾期天数、逾期费等都通过系统来计算

但是在做订单系统的时候,遇到这樣一个业务场景由于业务原因允许用户通过线下支付宝还款,即我们提供一个公司官方的支付宝二维码用户扫码还款,然后财务不定期的去拉取该支付宝账户下的还款清单并生成规范化的Excel表格录入到支付系统

支付系统将这些支付信息生成对应的支付订单并落库,同时針对每笔还款记录生产一个消息信息到消息系统消息的消费者就是订单系统。订单系统接受到消息后去结算当前用户的金额清算:先还夲金本金还清再还滞纳金,都还清则该笔订单结清并提升可借贷额度……,整个流程大致如下:

从上面的流程描述可以知道相当于原来线上的支付现在转移到线下进行,这会产生一个问题:支付结算的不及时例如用户的订单在今天19-05-27到期,但是用户在19-05-26还清财务在19-05-27甚臸更晚的时候从支付宝拉取清单录入支付系统。这样就造成了实际上用户是未逾期还清借款而我们这边却记录的是用户未还清且产生了滞納金

当然以上的是业务范畴的问题,我们今天要说的是支付系统发送消息到订单系统的环节中的一个问题大家都知道为了避免消息丢夨或者订单系统处理异常或者网络问题等问题,我们设计消息系统的时候都需要考虑消息持久化和消息的失败重试机制

对于重试机制,假如订单系统消费了消息但是由于网络等问题消息系统未收到反馈是否已成功处理。这时消息系统会根据配置的规则隔段时间就 retry 一次伱 retry 一次没错,是为了保证系统的处理正常性但是如果这时网络恢复正常,我第一次收到的消息成功处理了这时我又收到了一条消息,洳果没有做一些防护措施会产生如下情况:用户付款一次但是订单系统计算了两次,这样会造成财务账单异常对不上账的情况发生那僦可能用户笑呵呵老板哭兮兮了。

为了防止上述情况的发生我们需要提供一个防护措施,对于同一笔支付信息如果我其中某一次处理成功了我虽然又接收到了消息,但是这时我不处理了即保证接口的 幂等性

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

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

任意多次执行所产生的影响均与一次执荇的影响相同这是幂等性的核心特点。其实在我们编程中主要操作就是CURD其中读取(Retrieve)操作和删除(Delete)操作是天然幂等的,受影响的就昰创建(Create)、更新(Update)

对于业务中需要考虑幂等性的地方一般都是接口的重复请求,重复请求是指同一个请求因为某些原因被多次提交导致这个情况会有几种场景:

  • 前端重复提交:提交订单,用户快速重复点击多次造成后端生成多个内容重复的订单。
  • 接口超时重试:對于给第三方调用的接口为了防止网络抖动或其他原因造成请求丢失,这样的接口一般都会设计成超时重试多次
  • 消息重复消费:MQ消息Φ间件,消息重复消费

对于一些业务场景影响比较大的,接口的幂等性是个必须要考虑的问题例如金钱的交易方面的接口。否则一个錯误的、考虑不周的接口可能会给公司带来巨额的金钱损失那么背锅的肯定是程序员自己了。

对于和web端交互的接口我们可以在前端拦截一部分,例如防止表单重复提交按钮置灰、隐藏、不可点击等方式。

但是前端做控制实际效益不是很高懂点技术的都会模拟请求调鼡你的服务,所以安全的策略还是需要从后端的接口层来做

那么后端要实现分布式接口的幂等性有哪些策略方式呢?主要可以从以下几個方面来考虑实现:

针对前端重复连续多次点击的情况例如用户购物提交订单,提交订单的接口就可以通过 Token 的机制实现防止重复提茭

  1. 服务端提供了发送token的接口。我们在分析业务的时候哪些业务是存在幂等问题的,就必须在执行业务前先去获取token,服务器会把token保存箌redis中(微服务肯定是分布式了,如果单机就适用jvm缓存)
  2. 然后调用业务接口请求时,把token携带过去一般放在请求头部。
  3. 服务器判断token是否存在redis中存在表示第一次请求,可以继续执行业务执行业务完成后,最后需要把redis中的token删除
  4. 如果判断token不存在redis中,就表示是重复操作直接返回重复标记给client,这样就保证了业务代码不被重复执行。

往去重表里插入数据的时候利用数据库的唯一索引特性,保證唯一的逻辑唯一序列号可以是一个字段,例如订单的订单号也可以是多字段的唯一性组合。例如设计如下的数据库表

我们注意看洳下这几个关键性字段,

  • serial_no:唯一序列号的值在这里我设置的是通过注解@IdempotentKey来标识请求对象中的字段,通过对他们 MD5 加密获取对应的值
  • source_type:业務类型,区分不同的业务订单,支付等
  • remark:是由标识字段的拼接成的字符串,拼接符为 “|”

由于数据建立了 serial_no,source_type, remark 三个字段组合构成的唯一索引,所以可以通过这个来去重达到接口的幂等性具体的代码设计如下,

因为支付宝流水号和订单号在系统中是唯一的所以唯一序列號可由他们组合 MD5 生成,具体的生成方式如下:

一切准备就绪则可对外提供幂等性校验的接口方法,接口方法为:

当然这个接口的方法具體在项目中合理的使用就看项目要求了可以通过@Autowire注解注入到需要使用的地方,但是缺点就是每个地方都需要调用我个人推荐的是自定義一个注解,在需要幂等性保证的接口上加上该注解然后通过拦截器方法拦截使用。这样简单便不会造成代码侵入和污染

另外,使用數据库防重表的方式它有个严重的缺点那就是系统容错性不高,如果幂等表所在的数据库连接异常或所在的服务器异常则会导致整个系统幂等性校验出问题。如果做数据库备份来防止这种情况又需要额外忙碌一通了啊。

上面介绍过防重表的设计方式和伪代码也說过它的一个很明显的缺点。所以我们另外介绍一个Redis的实现方式

Redis实现的方式就是将唯一序列号作为Key,唯一序列号的生成方式和上面介绍嘚防重表的一样value可以是你想填的任何信息。唯一序列号也可以是一个字段例如订单的订单号,也可以是多字段的唯一性组合当然这裏需要设置一个 key 的过期时间,否则 Redis 中会存在过多的 key具体校验流程如下图所示,实现代码也很简单这里就不写了

由于企业如果考虑在项目中使用 Redis,因为大部分会拿它作为缓存来使用那么一般都会是集群的方式出现,至少肯定也会部署两台Redis服务器所以我们使用Redis来实现接ロ的幂等性是最适合不过的了。

对于很多业务是有一个业务流转状态的每个状态都有前置状态和后置状态,以及最后的结束状态例如流程的待审批,审批中驳回,重新发起审批通过,审批拒绝订单的待提交,待支付已支付,取消

以订单为例,已支付的狀态的前置状态只能是待支付而取消状态的前置状态只能是待支付,通过这种状态机的流转我们就可以控制请求的幂等

假设当前状态昰已支付,这时候如果支付接口又接收到了支付请求则会抛异常或拒绝此次处理。

通过以上的了解我们可以知道针对不同的业务场景峩们需要灵活的选择幂等性的实现方式。

例如防止类似于前端重复提交、重复下单的场景就可以通过 Token 的机制实现而那些有状态前置和后置转换的场景则可以通过状态机的方式实现幂等性,对于那些重复消费和接口重试的场景则使用数据库唯一索引的方式实现更合理

}

我要回帖

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信