RPC接口不允许使用枚举类型。为什么?

2021-12-24 11:38:59 浏览数 (1)

前言

在说这个问题之前,先让我们看下相关的背景知识。

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、对于枚举类,可以封装成一个对象代替。

0 人点赞