| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> 网络协议 -> 为什么阿里巴巴RPC接口不允许使用枚举类型?,泛微网络java面试 -> 正文阅读 |
|
[网络协议]为什么阿里巴巴RPC接口不允许使用枚举类型?,泛微网络java面试 |
public?AResponse?doSth(ARequest?aRequest); } public?Class?AResponse{ private?Boolean?success; private?AType?aType; } public?enum?AType{ P_T, A_B } 然后B系统依赖了这个二方库,并且会通过RPC远程调用的方式调用AFacadeS
ervice的doSth方法。 public?class?BService?{ @Autowired AFacadeService?aFacadeService; public?void?doSth(){ ARequest?aRequest?=?new?ARequest(); AResponse?aResponse?=?aFacadeService.doSth(aRequest); AType?aType?=?aResponse.getAType(); } } 这时候,如果A和B系统依赖的都是同一个二方库的话,两者使用到的枚举AType会是同一个类,里面的枚举项也都是一致的,这种情况不会有什么问题。 但是,如果有一天,这个二方库做了升级,在AType这个枚举类中增加了一个新的枚举项P_M,这时候只有系统A做了升级,但是系统B并没有做升级。 那么A系统依赖的的AType就是这样的: public?enum?AType{ P_T, A_B, P_M } 而B系统依赖的AType则是这样的: public?enum?AType{ P_T, A_B } 这种情况下**,在B系统通过RPC调用A系统的时候,如果A系统返回的AResponse中的aType的类型为新增的P_M时候,B系统就会无法解析。一般在这种时候,RPC框架就会发生反序列化异常。导致程序被中断。** 原理分析 这个问题的现象我们分析清楚了,那么再来看下原理是怎样的,为什么出现这样的异常呢。 其实这个原理也不难,这类RPC框架大多数会采用JSON的格式进行数据传输,也就是客户端会将返回值序列化成JSON字符串,而服务端会再将JSON字符串反序列化成一个Java对象。 而JSON在反序列化的过程中,对于一个枚举类型,会尝试调用对应的枚举类的valueOf方法来获取到对应的枚举。 而我们查看枚举类的valueOf方法的实现时,就可以发现,如果从枚举类中找不到对应的枚举项的时候,就会抛出IllegalArgumentException: public?static?<T?extends?Enum>?T?valueOf(Class?enumType, String?name)?{ T?result?=?enumType.enumConstantDirectory().get(name); if?(result?!=?null) return?result; if?(name?==?null) throw?new?NullPointerException(“Name?is?null”); throw?new?IllegalArgumentException( "No?enum?constant?"?+?enumType.getCanonicalName()?+?“.”?+?name); } 关于这个问题,其实在《阿里巴巴Java开发手册》中也有类似的约定:  这里面规定"对于二方库的参数可以使用枚举,但是返回值不允许使用枚举"。这背后的思考就是本文上面提到的内容。 扩展思考 为什么参数中可以有枚举? 不知道大家有没有想过这个问题,其实这个就和二方库的职责有点关系了。 一般情况下,A系统想要提供一个远程接口给别人调用的时候,就会定义一个二方库,告诉其调用方如何构造参数,调用哪个接口。 而这个二方库的调用方会根据其中定义的内容来进行调用。而参数的构造过程是由B系统完成的,如果B系统使用到的是一个旧的二方库,使用到的枚举自然是已有的一些,新增的就不会被用到,所以这样也不会出现问题。 比如前面的例子,B系统在调用A系统的时候,构造参数的时候使用到AType的时候就只有P_T和A_B两个选项,虽然A系统已经支持P_M了,但是B系统并没有使用到。 如果B系统想要使用P_M,那么就需要对该二方库进行升级。 但是,返回值就不一样了,返回值并不受客户端控制,服务端返回什么内容是根据他自己依赖的二方库决定的。 但是,其实相比较于手册中的规定,我更加倾向于,在RPC的接口中入参和出参都不要使用枚举。 一般,我们要使用枚举都是有几个考虑:
不可否认,使用枚举确实有一些好处,但是我不建议使用主要有以下原因:
我其实建议大家在接口中使用字符串代替枚举,相比较于枚举这种强类型,字符串算是一种弱类型。 如果使用字符串代替RPC接口中的枚举,那么就可以避免上面我们提到的两个问题,上游系统只需要传递字符串就行了,而具体的值的合法性,只需要在A系统内自己进行校验就可以了。 为了方便调用者使用,可以使用javadoc的@see注解表明这个字符串字段的取值从那个枚举中获取。 public?Class?AResponse{ private?Boolean?success; /** *??@see?AType */ private?String?aType; } 对于像阿里这种比较庞大的互联网公司,随便提供出去的一个接口,可能有上百个调用方,而接口升级也是常态,我们根本做不到每次二方库升级之后要求所有调用者跟着一起升级,这是完全不现实的,并且对于有些调用者来说,他用不到新特性,完全没必要做升级。 还有一种看起来比较特殊,但是实际上比较常见的情况,就是有的时候一个接口的声明在A包中,而一些枚举常量定义在B包中,比较常见的就是阿里的交易相关的信息,订单分很多层次,每次引入一个包的同时都需要引入几十个包。 |
|
网络协议 最新文章 |
使用Easyswoole 搭建简单的Websoket服务 |
常见的数据通信方式有哪些? |
Openssl 1024bit RSA算法---公私钥获取和处 |
HTTPS协议的密钥交换流程 |
《小白WEB安全入门》03. 漏洞篇 |
HttpRunner4.x 安装与使用 |
2021-07-04 |
手写RPC学习笔记 |
K8S高可用版本部署 |
mySQL计算IP地址范围 |
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/26 10:26:15- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |