最近在用dubbo的时候出现了一个问题就是 ‘部分的对象属性为null’
通过dubbo进行序列化和反序列话的时候发现有部分的属性为null
笔者反复的试验 发现这是一个类似mybatis 的一个机制 ‘父存子取(假的只是简单记忆)’ 也就是说在序列话的时候我们的数据存在对象的父类中 但是在子类的对象属性为null 那么在反序列的时候子类的方法会覆盖上去 也就是说反序列的时候会拿到null 这也就解释了为什么有部分对象属性为null的原因了
我们再来看下dubbo的源码看他是怎么实现的:
public JavaDeserializer(Class cl)
{
_type = cl;
_fieldMap = getFieldMap(cl);
.......
protected HashMap getFieldMap(Class cl)
{
HashMap fieldMap = new HashMap();
for (; cl != null; cl = cl.getSuperclass()) {
Field []fields = cl.getDeclaredFields();
for (int i = 0; i < fields.length; i++) {
Field field = fields[i];
if (Modifier.isTransient(field.getModifiers())
|| Modifier.isStatic(field.getModifiers()))
continue;
else if (fieldMap.get(field.getName()) != null)
continue;
......
private Object readObjectInstance(Class cl, ObjectDefinition def)
throws IOException
{
String type = def.getType();
String []fieldNames = def.getFieldNames();
......
public Object readObject(AbstractHessianInput in,
Object obj,
String []fieldNames)
throws IOException
{
try {
int ref = in.addRef(obj);
for (int i = 0; i < fieldNames.length; i++) {
String name = fieldNames[i];
//重名的话,取出的都是私有的属性
FieldDeserializer deser = (FieldDeserializer) _fieldMap.get(name);
if (deser != null) // 当in读到父类时,把本类的属性值覆盖掉了
deser.deserialize(in, obj);
else
in.readObject();
}
Object resolve = resolve(obj);
if (obj != resolve)
in.setRef(ref, resolve);
return resolve;
} catch (IOException e) {
throw e;
} catch (Exception e) {
throw new IOExceptionWrapper(obj.getClass().getName() + ":" + e, e);
}
}
这个类的构造方法里调用了这样的方法getFieldMap,把里面本类和父类的所有方法放到一个fieldMap里,因为是HashMap,为了保证方法名不覆盖,这个方法里做了一个操作就是fieldMap.get(field.getName()) != null,有的话就继续循环下去不覆盖,这样的话如果有同名的方法,那只有子类的方法在里面。还有这个类Hessian2Input要说下,其中的方法readObjectInstance,它会取到本类和父类的所有方法放到一个数组fieldNames下,这些说完了说到这里面反序列化的方法JavaSerializer的readObject,是按fieldNames数组循环取值,在流里面挨个取出来,一直赋给本类的set方法,先是有值的,到父类时,取到的为空,就把本类的值覆盖了。到这里原因就清楚了。