Dubbo 服务调用返回的对象部分属性返回为null

在使用Dubbo进行序列化和反序列化时遇到对象部分属性为null的问题。这个问题与Mybatis的'父存子取'机制类似,即在反序列化时,如果父类中的数据存在,而子类属性为null,则反序列化后的子类属性也会是null。深入研究Dubbo源码,发现在构造方法中,所有字段包括父类的都被收集到fieldMap中,反序列化时按照fieldNames数组顺序进行,导致父类的null值覆盖了子类的非null值。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近在用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方法,先是有值的,到父类时,取到的为空,就把本类的值覆盖了。到这里原因就清楚了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值