本文的“接口”

本文的-"接口",等同于 RPC 类协议/框架中的接口,例如SOAP, Apache Thrift, Apache Avro, Microsoft DCOM, WCF 及集团内最常用的 HSF, Dubbo 等等。此外,还有一些 RESTful 规范/框架(如Jax-RS),在使用体验上也非常类似于 RPC,虽然通常不被归属于RPC, 但本文中的提到某些原则可能同样适用。

一次典型的RPC 请求/响应包含以下几个步骤:

  • 1) 客户端发起一次方法调用
  • 2) 客户端将调用(接口+方法+参数)进行打包
  • 3) 客户端将打包后的内容发送到服务器端
  • 4) 服务器端收到数据并解析为一次方法调用
  • 5) 服务器端在某对象上执行方法(参数)调用
  • 6) 服务器端将得到调用返回值,并对其打包
  • 7) 服务器端将打包后的返回值发送给客户端
  • 8) 客户端收到响应并解析响应数据
  • 9) 客户端得到方法的返回值

由于 2)~8) 的步骤对客户端是透明的,看似乎是本地方法调用,但远程方法调用是不同于本地调用的,使用时也不应该忽视他们存在着不同。
虽然不少框架没有对接口作出更严格的语法限制,但实际使用起来也不能太过任性,适当遵循一些规则习俗,会减少一些不必要的麻烦。以下就过往使用的经验,列举一些较常见的问题。

“接口”的定义

远程接口调用过程,发生了一次数据交换,即使用参数换得一个返回值或异常,一个普通的接口可能是这样的

public interface DemoService {public ResultType doAnything(FooType arg1, BarType arg2) throws MyException;
}

不同于本地方法调用的是,远程方法对参数、返回值、异常的定义限制的越“严格”越好-从某种意义上说,参数、返回值、异常的类型都是应该是 Struct而非 Class,那么区别在哪、又为什么这么说呢?

  • 1) Struct 侧重于字段-值,不可被扩展 - 这意味着Client/Server 每一端都不可能在协商好接口定义后单方面对数据进行“画蛇添足”,也不可能发送对方也许会不知道的数据类型,保证双方对收到的数据不存在产生歧义的可能。
  • 2) Class 侧重于功能-方法,通常允许扩展-这意味着 Client/Server 都有可能向对方发送一个对方并不知道的类。比如Client 向 Server 发送了参数 FooType 的扩展类 FooTypeExt, 而 Server 可能因无法解释 FooTypeExt 而产生意外异常。

一些很可能产生歧义的接口定义:

  • 1) 参数类型限定太宽泛,想返回什么都人合乎语法,无法保证 Server 一定会理解该参数
public int saveData(Object data);
  • 2) 返回类型限定太宽泛,想返回什么都人合乎语法,无法保证 Client 一定会理解返回值
public Object saveData(int id);
  • 3) 使用基础/抽象类型,一方可以随意 override 掉 BaseType 的某些行为而使用对方产生某些意外的效果
public int saveData(BaseType data);
public AbstractType getData(int id);
  • 4) 泛型接口,不应当使用
public interface IMyAPI<T extends BaseType> {pulic saveData(T data);public T getData(int key);
}

这样的接口定义了啥?

  • 5) 泛型方法,不应使用
public <T> T getData(int key);

这样的接口定义了啥?

由于 Java 不支持 Struct,在实际开发中,理论上应该只使用 final 修饰的 POJO 类作为参数/返回值类型,即使参数/返回类型不是密封类,也要避免使用它们的扩展类;
在需要使用 List, Map 等时,虽然语法允许使用它们的任意扩展类,但最好只使用JRE 包含的类而不要随意扩展。

“接口”的发布

“接口” 是Client/Server 数据交换的契约,接口所在包要被 Client/Server 所共享,因此这个包中最好仅是包含接口以及与接口相关的参数类型、返回值类型、异常类型,及其它公用的常量、枚举、资源等等, 而不应该包含Client或Server功能的具体实现
一个常见的现象是接口类被打包在 xxxx-client.jar 中而发布,这种方式存在以下多种问题。

  • 1) server 上仅为了获得接口类,就需要部署 client.jar 及其全部依赖项,导致引用了很多冗余的包。
  • 2) 接口定义经过双方协商后不会轻易变更,但 xxxx-client.jar 因包含有功能实现而会经常更新,继而引起接口使用方的连锁更新,而实际上又是不必要的。
  • 3) 一些接口测试/分析工具,为了获得接口定义,同样也不得不部署整个的 client.jar 及其依赖项。
    另一个常见现在是接口类被打包在 xxxx-common.jar 中发布,如果 common 库中包含有复杂的功能实现,同样也会引发上面两个问题。

小结:接口定义与期所在的包是同命运的,接口不更新则包不应该更新,包若更新则是表示接口已变。因此,在打包和发布接口时,尽量遵循以下

  • a) 把接口类及期附属的参数/返回值/常量/资源等发布在一个 xxxx-api.jar (xxx-service/interface.jar等)包中;
  • b) 不要在这个包中发布Client/Server 上的功能实现类;
  • c) 如果有 Client/Server 共同的功能类,那么把它打包在另一个 xxxx-common.jar(xxxx-shared.jar等) 中;

接口设计的几个注意事项相关推荐

  1. java 接口api设计的注意事项_Java接口设计原则

    类原则 1.单一职责原则 – Single Responsibility Principle(SRP) 就一个类而言,应该仅有一个引起它变化的原因. 职责即为"变化的原因". 2. ...

  2. JAVA接口设计篇:这些都不知道,别说你懂接口设计

    背景 昨天测试提醒有个功能报错了,我看了下,发现接口有过更新. 然后顺便问了下开发同学,确实有更新. 他们的更新是把现有的接口进行了修改. 导致返回的数据结构变更了,以至于接口直接报错. 其实负责后端 ...

  3. 扒一扒DDR4的新功能和PCB设计上的一些注意事项--转

    扒一扒DDR4的新功能和PCB设计上的一些注意事项 转自 http://www.elecfans.com/d/906656.html DDR4新增了许多功能,这对于我们之前信手拈来的内存PCB设计又带 ...

  4. 基于高速51单片机的模拟USB接口设计

    基于高速51单片机的模拟USB接口设计 作者:廖颂文 摘要:参照AVRUSB技术给出了51单片机通过模拟USB通信的实现方法.用VC编写了上位机软件,通过libusb驱动实现了PC与ST12LE560 ...

  5. java 转账_JAVA实操项目:转账接口设计

    原标题:JAVA实操项目:转账接口设计 在一个项目中,一般都会支付相关的业务,而涉及到支付必定会有转账的操作,转账这一步想起来算是比较关键的部分,这个接口的设计能力,也大致体现出一个人的水平. 昨天碰 ...

  6. 基于FPGA的PCI接口设计

    1 PCI总线及其接口概述 PCI总线是高速同步总线,具有32bit总线宽度,工作频率是33MHz,最大传输率为132Mbyte/s,远远大于ISA总线5Mbyte/s的速率.PICMG(PCI工业计 ...

  7. Django博客系统注册(图形验证码接口设计和定义)

    1. 准备captcha包(该包用于生成图形验证码) 1.将生成图片验证码的库复制到新建的libs包中. 2.安装Python处理图片的库 这儿可能会变红显示错误: 解决方案:在虚拟环境中安装Pill ...

  8. 微服务之API网关接口设计

    微服务之API网关接口设计 API网关,顾名思义,就是外部到内部的一道门,其主要功能: 服务路由:将前段应用的调用请求路由定位并负载均衡到具体的后端微服务实例,对于前端应用看起来就是1个应用提供的服务 ...

  9. 蓝牙(BLE)应用框架接口设计和应用开发——以TI CC2541为例

    本文从功能需求的角度分析一般蓝牙BLE单芯片的应用框架(SDK Framework)的接口设计过程,并以TI CC2541为例说明BLE的应用开发方法. 一.应用框架(Framework) 我们熟知的 ...

最新文章

  1. c++ 获取当前时间_【Python】日期和时间
  2. 归纳几点html编码要素--杜绝浏览器不兼容
  3. 『Spring.NET+NHibernate+泛型』框架搭建之DAO(三)★
  4. 魔兽争霸3地图(WarIII Maps):梦若流星
  5. 沈航计算机考研真题,2018年沈阳航空航天大学考研真题硕士研究生入学考试试题...
  6. 值传递,引用传递,指针传递
  7. Spring Security 基于数据库的认证
  8. Spring框架学习(二)
  9. hihoCoder-1037-数字三角形(dp)
  10. 龙芯OpenJDK更新策略:没必要跟进小版本,最后大版本更新
  11. ARM上移植ser2net源码
  12. CiteSpace中的中介中心性(betweenness)的理解(包含度中心性(degree)、接近中心性(closeness))
  13. 论文阅读:《Connectionist Temporal Classification: Labelling Unsegmented Sequence Data with Recurrent Neu》
  14. android amr转换mp3格式文件,安卓批量amr转mp3 微信amr批量转换
  15. 华为大数据与阿里大数据的区别
  16. 河南这么大的省,也所谓的准一线,为什么IT行业就是发展不起来呢?
  17. 利用grub引导多系统debian8.0+win7+ubuntu16.04
  18. JS偏函数、组合函数、缓存函数
  19. 关于巨量算数jsvmp简单还原signature思路
  20. 部署Kubernetes集群(二进制 v1.18.8版)

热门文章

  1. 服务器c盘windows文件夹太大,Win10C盘windows文件夹过大怎么办?Win10C盘windows文件夹过大的解决方法...
  2. golang new与make的一点区别理解
  3. SpringBoot 自动配置原理
  4. java类型转换_Java类型转换
  5. 贴片电阻上写着“0”,所谓的“零欧电阻”,在电子电路中的用处很大
  6. 使用Go语言创建WebSocket服务
  7. springbatch导出mysql数据到外部文件
  8. Redis设计与实现阅读总结(一)数据结构和对象
  9. 【Windows】DACL SACL
  10. C#不同窗体间通信,数据传递