Dubbo序列化对象的一个坑
--洱涷Zz
今天在处理项目问题的时候遇到了Dubbo
序列化对象的一个坑,记录一下:
大致是同事在调用Dubbo
rpc
接口的时候发现返回的值和预期的返回值不符,预期是返回一个对象的集合,但是返回的集合里是hashMap
,查看他们代码解决后是发现他们的消费者端对返回对象的路径定义与我们服务提供者端的路径不一致,导致返回的数据和预期不符。这个解决起来很简单,保持路径一致就可以。(最好就是将对象定义成公共的,可以很好的避免这些问题)
但是为什么会出现这种情况呢?为什么会出现这个hashMap
呢?
一步一步理下来发现是消费端和服务端在进行类的序列化
和反序列化
时出现的问题,首先Java中进行反序列化的类是JavaSerializer
,这个类的构造方法里调用了这样的方法:getFieldMap
,把里面本类和父类的所有方法放在fieldMap
里,因为是hashMap
,为了保证方法名不覆盖,这个里面就做了一个操作就是:
fieldMap.get(field.getName())!=null;
在消费者端进行反序列化时,会判断该路径下类名是否存在,如果存在,那么就对返回的集合对象进行循环赋值,如果不存在则会直接返回这个hashMap
于此,问题的原因找到了,但是思考一下:
- 既然是序列化的问题,那么如果是消费端和服务端的对象处于相同路径下,其序列化产生的
uid
不同会造成什么问题呢? - 如果是不同路径下,序列化的
uid
相同会产生什么问题? - 如果是相同路径下,对象还有父对象且其中部分属性相同,会有什么问题?
- 如果是对象路径、
uid
、属性都相同但是没有实现序列化会有什么问题?
结论:
-
由上述反序列化时所调用的方法可知,其在反序列化时是根据方法名和路径去进行匹配赋值的,只要路径相同,名称相同,无论
uid
是什么,都可以成功返回对象集合,-
继续引深,为什么呢?按照java应该是不可以实现的
-
开始困扰了好久,查资料看到一句话,“
hessian2
序列化:hessian
是一种跨语言的高效二进制序列化方式。但这里实际不是原生的hessian2
序列化,而是阿里修改过的hessian lite
,它是dubbo RPC
默认启用的序列化方式。”。后来就想,是不是因为序列化方式有关,会不会是Hessian
序列化时并不会在意serialVersionUID
的变化。为证实心中的疑虑。分别采用了Hessian和java两种序列化方式进行验证。 -
这里有2个工程,一个发送端,一个接收端,采用SpringBoot启动,两个工程里面都分别载入了实体对象Person。用于测试对象serialVersionUID相同和不相同的情况。
-
1.第一个工程,是传输对象接受端,这里反序列化。serializabletest-server。3个主类
1.1.Person.java 传输对象。@ToString @Data public class Person implements Serializable { private static final long serialVersionUID = -1923645274767028479L; private String[] address; private String name; private int phone; }
1.2. HessianController.java hessian反序列化接受类。通过一个Controller接受http提交过来的对象信息
@Slf4j @RestController @RequestMapping("/hessian") public class HessianController { @RequestMapping(value = "/hello") public String helloWorld(HttpServletRequest request, HttpServletResponse response) throws IOException { log.info("hessian反序列化开始------------------------"); ServletInputStream sis = request.getInputStream(); Hessian2Input h2i = new Hessian2Input(sis)
-