最近工作中遇见了一个小问题,在此记录一下,大致是这样的,有一父类,有一个属性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. ACE代码编辑器,代码提示,添加自定义数据

    //设置自动提示代码 var setCompleteData = function(data) { var langTools = ace.require("ace/ext/language ...

  2. 牛顿方法(Newton-Raphson Method)

    本博客已经迁往http://www.kemaswill.com/, 博客园这边也会继续更新, 欢迎关注~ 牛顿方法是一种求解等式的非常有效的数值分析方法. 1.  牛顿方法 假设\(x_0\)是等式的 ...

  3. IOS UIScrollView + UIButton 实现segemet页面和顶部标签页水平滚动效果

    很长一段时间没有写博客了,最近在学习iOS开发,看了不少的代码,自己用UIScrollView和UIButton实现了水平滚动的效果,有点类似于今日头条的主界面框架,效果如下: 代码如下: MyScr ...

  4. MSIL 教程(三):类和异常处理(转)

    转自:http://www.cnblogs.com/Yahong111/archive/2007/08/16/857771.html 续上文[翻译]MSIL 教程(二):数组.分支.循环.使用不安全代 ...

  5. Codeforces Round #195 A B C 三题合集 (Div. 2)

    A 题 Vasily the Bear and Triangle 题目大意 一个等腰直角三角形 ABC,角 ACB 是直角,AC=BC,点 C 在原点,让确定 A 和 B 的坐标,使得三角形包含一个矩 ...

  6. 在自己的框架中引用 PHPExcel

    如果直接在框架中的controller中直接引用 xxxx/PHPExcel.php,由于框架中有autoload 与PHPExcel的autoload冲突(加载目录原因), 那么在不想做太多修改的情 ...

  7. 强(strong)、软(soft)、弱(weak)、虚(phantom)引用

    https://github.com/Androooid/treasure/blob/master/source/lightsky/posts/mat_usage.md 1.1 GC Root JAV ...

  8. SNF开发平台WinForm之八-自动升级程序部署使用说明-SNF快速开发平台3.3-Spring.Net.Framework

    9.1运行效果: 9.2开发实现: 1.首先配置服务器端,把“SNFAutoUpdate2.0\服务器端部署“目录按网站程序进行发布到IIS服务器上. 2.粘贴语句,生成程序 需要调用的应用程序的Lo ...

  9. Tmux 常用命令与快捷键

    命令与别名 attach-session [-dr] [-t target-session] 别名 attach,连接会话. detach-client [-P] [-a] [-s target-se ...

  10. 爬虫技术 -- 基础学习(三)理解URL和URI的联系与区别

    网络爬虫的基本操作是抓取网页.首先要了解下URL~~ 在理解URL之前,先了解下URI,这两个概念我曾经混淆过~@_@|| 什么是URI? Web上每种可用的资源,如:html文档.视频,图片等都由一 ...