前言
在说这个问题之前,先让我们看下相关的背景知识。
RPC简介
RPC是Remote Procedure Call的缩写。中文名是:远程服务调用。简单来说就是一个节点提供服务(称为服务端),一个节点消费服务(客户端)。
RPC通信方式
PRC的服务端和客户端之间的通信协议是TCP/IP。但是,你肯定会有疑惑,服务端提供的服务中类定义,客户端是怎么知道的呢? 答案就是序列化和反序列化。序列化的作用:将结构类信息转换成字节码供不同服务之间的传递。反序列化:将接收到信息按照约定还原成结构信息。
实战解析
翠花上图
话不多说,直接上图,上代码。
上图中,客户端提供了一个可以查询角色战斗力的服务,并打成了包供客户端查看消费。但是,服务端偷偷摸摸的而升级二方包版本到了2.0,没有告诉客户端。人狠话少,直接开了属于是。
翠花上代码
版本1.0 的枚举类。可以看出来孙悟空还是比三太子厉害的,排在了前面。
1.0
代码语言:javascript复制public enum RoleEnum {
WU_KONG(0,"孙悟空"),
NE_ZHA(1,"哪吒");
int code;
String desc;
RoleEnum(int code, String desc) {
this.code = code;
this.desc = desc;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
}
复制代码
好。下面我们模拟下序列化和反序列化。注意:RPC服务中一般将枚举类序列化成名称的形式,反序列化在通过valueOf()的方式进行。
代码语言:javascript复制 // 客户端,对RoleEnum序列化。
String jsonString = JSON.toJSONString(RoleEnum.values());
System.out.println("序列化");
System.out.println(jsonString);
//反序列化
List<RoleEnum> roleEnumList = JSON.parseArray(jsonString, RoleEnum.class);
System.out.println("反序列化");
roleEnumList.stream().forEach(e -> System.out.println(e.toString()));
复制代码
运行过后的控制台:
代码语言:javascript复制序列化
["WU_KONG","NE_ZHA"]
反序列化
WU_KONG
NE_ZHA
复制代码
可以看出。当是版本1.0的时候,客户端能够正确的解析出来谁才是第一。
2.0
好。下面,服务端偷偷摸摸的又在擂台上加上了一名重量级选手,猪八戒。 我们看下枚举类
代码语言:javascript复制public enum RoleEnum {
WU_KONG(0,"孙悟空"),
NE_ZHA(1,"哪吒"),
BA_JIE(2,"猪八戒");
int code;
String desc;
RoleEnum(int code, String desc) {
this.code = code;
this.desc = desc;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
}
复制代码
我这里偷个懒,直接手动模拟下服务端升级二方包版本2.0后,序列化的RoleEnum形式为:
代码语言:javascript复制序列化
["WU_KONG","NE_ZHA","BA_JIE"]
复制代码
好开始执行反序列化
代码语言:javascript复制public class Test01 {
public static void main(String[] args) {
// 客户端,对RoleEnum序列化。
//String jsonString = JSON.toJSONString(RoleEnum.values());
System.out.println("序列化");
String jsonString = "["WU_KONG","NE_ZHA","BA_JIE"]";
System.out.println(jsonString);
//反序列化
List<RoleEnum> roleEnumList = JSON.parseArray(jsonString, RoleEnum.class);
System.out.println("反序列化");
roleEnumList.stream().forEach(e -> System.out.println(e.toString()));
}
}
复制代码
开始打擂台,执行。。。 咦,咋报错了呢。
代码语言:javascript复制序列化
["WU_KONG","NE_ZHA","BA_JIE"]
反序列化
WU_KONG
NE_ZHA
Exception in thread "main" java.lang.NullPointerException
at com.pinfine.test.Test01.lambda$main$0(Test01.java:26)
at java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1380)
at java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:580)
at com.pinfine.test.Test01.main(Test01.java:26)
复制代码
从报错信息可以看出,出现了空指针。也就是调用枚举类的valueOf()方法出现的错误。是因为八戒只在服务端提供2.0的二方包才有,但是客户端还是1.0版本,里面自然没有八戒。根据名称自然解析不出来八戒楼。
建议
1、RPC提供服务的时候,禁止将枚举类作为参数返回,也不能封装到POJO对象中返回。
2、对于枚举类,可以封装成一个对象代替。