• 深入学习Motan系列(五)—— 序列化与编码协议


    一、序列化

    1.什么是序列化和反序列化?

    序列化:将对象变成有序的字节流,里面保存了对象的状态和相关描述信息。

    反序列化:将有序的字节流恢复成对象。

    一句话来说,就是对象的保存与恢复

    为什么需要这个东西。它的作用呢,就是持久化(比如讲内容保存在计算机上)和进程间传递。因为计算机是二进制的,网络间传输东西也是通过二进制来传递的,所以需要将对象变成bytes再进行传递。

    2.序列化的使用

    使用序列化的demo,我不写了,网上一堆。里面用到的ObjectOutputStream很重要,我们看看它的介绍(当然去看JDK的文档了,最权威)

    地址如下:https://docs.oracle.com/javase/8/docs/api/

    中文版:https://blog.fondme.cn/apidoc/jdk-1.8-google/

    只用继承了Serializable接口的类才能被写进字节流中(进行序列化),序列化编码时包含的内容有:类名,类签名,对象字段的值和数组,以及初始化对象引用的closure(汉语没想到怎么表达它)。默认的序列化机制可以写入对象,类签名,所有non-transientnon-static的字段。

    默认的序列化机制使用:继承Serializable接口,就可以使用了;若是想自定义序列化机制(出于信息安全和效率的目的),需要实现下面的方法:readObject() writeObject()

    readObjectNoData()。实现Externalizable接口可以完全控制对象序列化内容和格式(目前,我没见过Externalizable接口,稍后,尝试分析hession序列化协议,看看里面是否会有这个接口)。

    3.序列化步骤

    序列化算法步骤如下:
    ◆将对象实例相关的类元数据输出。【元数据】
    ◆递归地输出类的超类描述直到不再有超类。【超类描述】
    ◆类元数据完了以后,开始从最顶层的超类开始输出对象实例的实际数据值。【超类-类的实际数据值】
    ◆从上至下递归输出实例的数据【实例数据值】

     (序列化步骤这部分,摘自https://blog.csdn.net/suyebiubiu/article/details/78780941)

    4.序列化协议之间比较

    推荐文章:https://tech.meituan.com/serialization_vs_deserialization.html

    (上面这篇文章写的确实非常好,此外,自己没有用过那么多的序列化协议,它们之间的好坏,无法做出衡量判断。每篇博文的记录,可以看作是知识的分享,更重要的是记录自己学习的脚印)

    5.Hession序列化方式

    Motan中使用的是Hession协议进行序列化的。接下来,走一遍,看看Hession的使用和里面的东西。

     1 public class Demo {
     2 
     3     public static void main(String args[]) throws IOException, InstantiationException, IllegalAccessException {
     4             UserInfo user = new UserInfo();
     5             user.setUsername("hello world");
     6             user.setPassword("buzhidao");
     7             user.setAge(21);
     8 
     9             ByteArrayOutputStream os = new ByteArrayOutputStream();
    10             //Hessian的序列化输出
    11             HessianOutput ho = new HessianOutput(os);
             // 关键内容在下面这一行中
    12 ho.writeObject(user); 13 14 byte[] userByte = os.toByteArray(); 15 ByteArrayInputStream is = new ByteArrayInputStream(userByte); 16 17 18 //Hessian的反序列化读取对象 19 HessianInput hi = new HessianInput(is); 20 UserInfo u = (UserInfo) hi.readObject(); 21 System.out.println("姓名:" + u.getUsername()); 22 System.out.println("年龄:" + u.getAge()); 23 24 } 25 26 }
    ho.writeObject(user);
     1   public void writeObject(Object object)
     2     throws IOException
     3   {
     4     if (object == null) {
     5       writeNull();
     6       return;
     7     }
     8 
     9     Serializer serializer;
    10     // 这里是一个工厂方法,依据被序列化内容的不同(是int,还是String,是long,还是其他Object,.etc)来选择合适的序列化器
    // 最后经过一系列的处理,返回UnsafeSerializer
    11 serializer = _serializerFactory.getSerializer(object.getClass()); 12 13 serializer.writeObject(object, this); 14 }

    然后,来到下面的处理(中间过程代码有省略)

     1 protected void writeObject10(Object obj, AbstractHessianOutput out)
     2     throws IOException
     3   {
     4     for (int i = 0; i < _fields.length; i++) {
          // 利用前面初始化时,已经确认的字段对应的序列化器,分别对字段的值进行序列化
    // 比如,String类型的字段,用StringFieldSerializer序列化器来处理
    5 Field field = _fields[i]; 6 7 out.writeString(field.getName()); 8 9 _fieldSerializers[i].serialize(out, obj); 10 } 11 12 out.writeMapEnd(); 13 }

    到这里,基本算是完成序列化的过程。我们看到的很简单,其实,内部的对底层的处理比较复杂,比如,序列化时,如何生成体积更小的byte,到底为什么速度更快等。这些问题,不在本文讨论范围内。

    6.问题

    在网上看到一个小列子,代码跟上文中的Demo 代码一样,区别在与:父类有三个属性,子类有一个同名属性。

     1 public class UserInfo extends User { 6     private String username ;
    15 }
    1 public class User implements Serializable {
    2     private String username ;
    3     private String password;
    4     private Integer age;
    5 }

    这样的话,用demo例子进行序列化与反序列化的时候,发现发序列化之后,demo中21行,u.getUsername()的值为null。这个原因不是出在序列化这里,而是由于java内部机制,具体原因正在调查中,有知道的,望前辈赐教。

    二、Motan编码协议

    首先,复习一下基础知识:

    字     word
    字节  byte
    位     bit
    字长是指字的长度

    1字节=8位(1 byte = 8bit)           一个字节的字长是8
    1字=2字节(1 word = 2 byte)      一个字的字长为16
     -----------------------------------------------------------------------------------

     数据协议= 协议头 + 协议体

     header:  16个字节
     0-15 bit     :  magic(魔法数字)
    16-23 bit    :  version (版本号)
    24-31 bit    :  extend flag , 其中: 29-30 bit: event 可支持4种event,比如normal, exception等,  31 bit : 0 is request , 1 is response
    32-95 bit    :  request id
    96-127 bit  :  body content length

    body部分就是利用序列化协议将request变成bytes[]

    最后,head+body,两者进行结合,通过Netty进行传输。

  • 相关阅读:
    关于时间的一些总结和全屏的一个知识点和百度的一道算法题
    关于超高频的一些研究
    Windows程序设计小结1
    windows系统Java环境配置
    第六章 事务与并发控制
    第五章 存储过程&触发器
    第四章 T-SQL编程
    第三章 数据库查询
    第二章 表的操作
    第一章 数据库的创建
  • 原文地址:https://www.cnblogs.com/lihao007/p/9942994.html
Copyright © 2020-2023  润新知