首先交代背景,前几天遇到一个小bug,因为其余系统的一个DTO子类和父类有一个字段名重复了,因此致使我set的子类字段那边拿不到值。改起来很简单嘛,让对面把子类的字段删掉就好,可是拿不到值的缘由让我想了好久,很明显是序列化和反序列化的过程当中这个字段的值丢失了,可是究竟是在哪一步呢?仍是决定看看源码给本身一个答案。java
首先先肯定协议和序列化的方式:apache
<dubbo:protocol name="dubbo" port="${dubbo.port}" host="${dubbo.host}"/>
ok,dubbo协议,没有配序列化方式,那再来找一下dubbo默认的序列化方式:
首先找到了这个包:数组
而后在Serialization接口(实现一些自定义序列化扩展用的)中发现了默认序列化的方式是hessian2spa
而后经过Hessian2Serialization的serialize方法和deserialize方法找到了Hessian2ObjectOutput、Hessian2ObjectInput这个两个类,以后经过里面的writeObject方法和readObject方法,找到了这两个类:JavaSerializer和JavaDeserializer。就是默认的序列化器和反序列化器。debug
首先咱们来看序列化:
构造方法:code
咱们看看他干了个什么事
首先检查了有没有writeReplace方法
而后把全部声明的字段放到数组中遍历,而后把除了transient和static修饰的字段放到ArrayList中去
而后往上找父类执行相同操做
而后把全部符合条件的字段放到一个Field数组里面,先放基本数据类型,再放引用数据类型
最后把字段放入对应类型的序列化器中去
获得一个FieldSerializer序列化器数组xml
咱们仍是继续看writeObject方法接口
主要是第二张图的3个方法,作的事情大概就是循环序列化field的名和值ip
下面再来看看反序列化:
构造方法:文档
这里大概作了3个事
获取fieldMap,方法以下:
获取readResolve方法
获取全部构造器
遍历构造器数组找到cost最小的最佳构造器
而后用最佳构造器进行构造,方法以下:
先看构造器方法,基本数据类型的话返回包装类型,引用数据类型返回null
主要咱们来看获取fieldMap的时候。和序列化时相同,先取子类再取父类,原本觉得到这就结束了,但是看到了一行校验
fieldMap.get(field.getName()) == null
若是父类的字段名和子类字段名相同,会跳过该循环,也就是说只会有子类的值,那为何还会覆盖?
看最后一个readMap方法:
debug发现值被覆盖就是在这里操做的
deser.deserialize(in, obj);
子类set过值之后,父类过来也会拿到子类的反序列化器,把子类的值覆盖掉。
最后,那为何会到readMap这一步呢?
debug发现SerializerFactory拿到反序列化器后会执行一个readMap操做
基本上就到这里了,最主要的缘由仍是readMap方法,并非不少博文说的fieldMap。若是哪里有不对的地方欢迎指出、讨论以便及时修改。
参考文档:连接描述