最近工作中遇见了一个小问题,在此记录一下,大致是这样的,有一父类,有一个属性traceId,主要是记录日志号,这样可以把所有日志串起来,利于排查问题,所有的pojo对象继承于此,但是其中一同事在子类pojo中也增加了这一个属性,在消费者端给traceId设置了值,但经过序列化解析后,提供者端这个traceId时,值为空,解决问题很简单啊,把子类中的traceId属性去掉搞定。

虽然问题很好解决但是这让笔者很懵逼啊,什么状况,都清楚地,实例化的子类,私有属性,取的肯定是实例设定的值,虽然我对此深信不疑,但是这还是让我怀疑了我自己,于是写了如下一些代码的验证这个问题。

1.先把问题抛出来一下。

Consumer端代码

@Setter
@Getter
@ToString
public class BaseBean implements Serializable {
private String xxx;
private String yyy;
private Integer zzz;
}
@Setter
@Getter
@ToString
public class Bean extends BaseBean {
private String xxx;
private String yyy;
private Integer zzz;
private String myStr;
}
public class Consumer {

    public static void main(String[] args) throws Exception {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
new String[] { "applicationContext.xml" });
context.start(); DemoService demoService = (DemoService) context.getBean("demoService");
Bean bean = new Bean();
bean.setMyStr("123");
bean.setXxx("xxx");
bean.setYyy("yyy");
bean.setZzz(789);
String hello = demoService.serTest(bean);
System.out.println(hello);
System.in.read();
}

Provider端代码

public class DemoServiceImpl implements DemoService {
public String serTest(Bean bean) {
System.out.println(bean);
return "123";
}
}

运行结果如下

2.Java中序列化就真的会出现这样的问题?

代码如下

public class TestSeriali {
public static void main(String[] args) throws IOException, ClassNotFoundException {
Bean bean = new Bean();
bean.setMyStr("123");
bean.setXxx("xxx");
bean.setYyy("yyy");
bean.setZzz(789);
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("chongming"));
out.writeObject(bean);
System.out.println("序列化完毕..");
out.close(); ObjectInputStream in = new ObjectInputStream(new FileInputStream("chongming"));
Bean beanResult = (Bean) in.readObject();
System.out.println("反序列化完毕..");
System.out.println(beanResult);
}
}

这段代码很显然父类三个属性,子类四个属性,其中三个与父类相同。代码运行结果如下

注:dubbo支持的其余集中序列化方式也做了验证,结果都是一样的,在这里就略过了。

这段代码证实了笔者一直的想法还是对的,但是问题就是出在dubbo的反序列化了。好吧翻翻dubbo的反序列化的源码吧,看看到底是咋回事

3.具体原因研究

代码比较多,挑几点重要的记录下,首先反序列化的类是JavaSerializer。

这个类的构造方法里调用了这样的方法getFieldMap,把里面本类和父类的所有方法放到一个fieldMap里,因为是HashMap,为了保证方法名不覆盖,这个方法里做了一个操作就是fieldMap.get(field.getName()) != null,有的话就继续循环下去不覆盖,这样的话如果有同名的方法,那只有子类的方法在里面。还有这个类Hessian2Input要说下,其中的方法readObjectInstance,它会取到本类和父类的所有方法放到一个数组fieldNames下,这些说完了说到这里面反序列化的方法JavaSerializer的readObject,是按fieldNames数组循环取值,在流里面挨个取出来,一直赋给本类的set方法,先是有值的,到父类时,取到的为空,就把本类的值覆盖了。到这里原因就清楚了。

主要的代码贴下来好了,如下

JavaSerializer构造方法及getFieldMap方法,获取到fieldMap

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;
......
Hessian2Input的readObjectInstance
private Object readObjectInstance(Class cl, ObjectDefinition def)
throws IOException
{
String type = def.getType();
String []fieldNames = def.getFieldNames();
......

JavaSerializer的readObject,这个贴的全一点

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);
}
}

其中注释俩句是笔者加的,在此原因也找到了,问题很好解决,这部分源码也不是很难,这些全是自己翻源码看的,可能我的理解也不完全对,如果不对谁看见了,欢迎交流。

dubbo序列化的一点注意的更多相关文章

  1. 热部署环境下,dubbo序列化的bug和优化

    一.问题的发现与解决 (1)     在热部署下,使用dubbo的序列化一个pojo对象,反序列化时报错:ClassNotFoundException. 最后发现原因是我们的框架选择使用了java序列 ...

  2. Dubbo序列化多个CopyOnWriteArrayList对象变成同一对象的一个大坑!!

    环境: win10 + jdk 1.8 + dubbo 2.5.10 问题描述: 当一个对象(此对象内包含多个CopyOnWriteArrayList对象) 作为参数调用RPC接口后, 服务提供者拿到 ...

  3. dubbo序列化

    序列化:把对象转换为字节序列的过程称为对象的序列化. 反序列化:把字节序列恢复为对象的过程称为对象的反序列化. dubbo 支持多种序列化方式并且序列化是和协议相对应的.比如:dubbo协议的 dub ...

  4. dubbo序列化hibernate.LazyInitializationException could not initialize proxy - no Session懒加载异常的解决

    dubbo序列化,hibernate.LazyInitializationException could not initialize proxy - no Session懒加载异常的解决 转载声明: ...

  5. dubbo 序列化 问题 属性值 丢失 ArrayList 解决

    参考文章:http://blog.csdn.net/wanyanxgf/article/details/6944733 http://tianya23.blog.51cto.com/1081650/5 ...

  6. .NET序列化的一点技巧(附Demo)

    阅读目录 介绍 详细 处理 结论 Demo下载 介绍 序列化是将对象状态转换为可保持或传输的形式的过程.序列化的补集是反序列化,后者将流转换为对象.这两个过程一起保证数据易于存储和传输. .NET F ...

  7. .NET序列化的一点技巧

    介绍 序列化是将对象状态转换为可保持或传输的形式的过程.序列化的补集是反序列化,后者将流转换为对象.这两个过程一起保证数据易于存储和传输. .NET Framework 提供了两个序列化技术: 二进制 ...

  8. dubbo 序列化机制之 hessian2序列化实现原理分析

    对于远程通信,往往都会涉及到数据持久化传输问题.往大了说,就是,从A发出的信息,怎样能被B接收到相同信息内容!小点说就是,编码与解码问题! 而在dubbo或者说是java的远程通信中,编解码则往往伴随 ...

  9. Dubbo 序列化协议 5 连问,你接得住不?

    1)dubbo 支持哪些通信协议? 2)支持哪些序列化协议? 3)说一下 Hessian 的数据结构? 4)PB 知道吗? 5)为什么 PB 的效率是最高的? 面试官心理分析 上一个问题,说说 dub ...

随机推荐

  1. 数据仓库与ODS的区别

    我在公司的数据部门工作,每天的订单类数据处理流程大致如下: 删除分析数据库的历史订单数据 全量更新订单数据到分析数据库.(由于订单核心数据不大,所以经受得起这么折腾) 将数据简单清洗,并生成数据集市层 ...

  2. oracle 数据库时间类型为字符串 时间范围大小查询

    select * from invoicedetail t2 where t2.Memo is null and to_char(to_date(t2.PrintDate,'yyyy-MM-dd hh ...

  3. Visual Studio快捷键 [VS2008/VS2005]快捷键

    VS系统通用快捷键: 1.自动排版(类似VC6中的Alt+F8) 编辑.格式化选定内容 Ctrl + K,Ctrl + F 根据周围的代码行,正确缩进选定的代码行. 2.注释与去掉注释功能. 编辑.注 ...

  4. Android开发中内存和UI优化

    1.内存||效率 GC这东西对于开发人员用起来比较爽,但对于技术总监或产品总监来说,他们并不在乎,在乎的是用户运行App的流畅度,待你开发完了,笑眯眯的走过来,让你测试N个适配器,烦都烦死你. 说到这 ...

  5. 如何在IIS7或IIS7.5中导入导出站点及应用程序池.

    为实现负载平衡,我们可能会使用多个WEB服务器,也就会需要给多个IIS配置同样的站点和应用程序池.那么我们需要一个一个的重新建吗?当然不用,我们只需要一些简单的命令就可以在IIS7(Windows S ...

  6. Windows 7远程桌面连接Ubuntu 16.04

    转自:http://jingyan.baidu.com/article/8ebacdf0cdc64949f75cd555.html 从Windows 7远程到Windows系统比较简单,只要对方电脑开 ...

  7. [转]OOPC:Object-Oriented Programming in C

    转载自:http://www.cnblogs.com/stli/archive/2010/10/16/1853190.html OOPC是指OOP(Object-Oriented Programmin ...

  8. HTML5[7]: 实现网页版的加载更多

    理所当然,jQuery出场: $(function() { $(window).scroll(function() { if($(this).scrollTop() + $(this).innerHe ...

  9. 【转】在web 项目使用了ReportViewer时出错

    ”应用程序中的服务器错误. -------------------------------------------------------------------------------- 分析器错误 ...

  10. 【解决方案】VS2013外部工具中添加ildasm.exe

    VS2013安装在Win8.1的操作系统中,开始屏幕中找不到ildasm.exe没有显示,于是下面提供了一种方法将ildasm.exe工具添加到VS2013外部工具中,并将反编译的代码输出到VS201 ...