美文网首页
序列化和反序列化原理分析

序列化和反序列化原理分析

作者: 剑道_7ffc | 来源:发表于2020-03-12 07:29 被阅读0次

    Java领域的对象如何传输

    基于socket进行对象传输

    当对象没有被序列化时,报异常(java.io.NotSerializableException: com.my.User
    );通过对象实现 Serializable 接口就可以解决这个问题。

    了解序列化的意义

    序列化把对象-->可存储或可传输的过程,即对象-->字节数组,解决jvm的对象的持久化或跨服务传输的问题。
    反序列化则相反

    序列化的高阶认识

    java原生序列化

    通过ObjectOutputStream和ObjectInputStream来实现序列化和反序列化

        public <T> byte[] serialize(T obj) {
            ByteArrayOutputStream byteArrayOutputStream=
                    new ByteArrayOutputStream();
            try {
                ObjectOutputStream outputStream=
                        new ObjectOutputStream(byteArrayOutputStream);
    
                outputStream.writeObject(obj);
    
                return  byteArrayOutputStream.toByteArray();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return new byte[0];
        }
        public <T> T deserialize(byte[] data, Class<T> clazz) {
            ByteArrayInputStream byteArrayInputStream=new ByteArrayInputStream(data);
            try {
                ObjectInputStream objectInputStream=
                        new ObjectInputStream(byteArrayInputStream);
    
                return (T) objectInputStream.readObject();
    
            } catch (IOException e) {
                e.printStackTrace();
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
            return null;
        }
    

    serialVersionUID 的作用

    作用

    来验证版本的一致性,反序列化serialVersionUID和实体类的serialVersionUID,若一致则可以进行反序列化,若不一致,则抛出异常InvalidCastException如这种场景:隐式声明序列化+序列化;修改本地实体类的内容;再进行反序列化会抛出InvalidCastException。

    生成方法

    1 隐式:编译器会默认生成一个
    2 显示:private static final long serialVersionUID

    生成规则

    根据类名、接口名、成员方法及属性等来生成一个 64 位的哈希字段即是序列化,类似于指纹算法,只要内容发生修改,则UID就不一样。

    Transient 关键字

    若变量加上Transient,则阻止该变量序列化,在被反序列化后,变量会被初始化默认值。

    绕开 transient 机制的办法

    通过增加writeObject和readObject的方法来解决,该方法在ObjectInputStream 和 ObjectOutputStream通过反射调用

    public class User {
        private static final long serialVersionUID = -434539422310062943L;
        private String name;
        private int age;
    
        private void writeObject(java.io.ObjectOutputStream s) throws IOException {
            s.defaultWriteObject();
            s.writeObject(name);
        }
    
        private void readObject(java.io.ObjectInputStream s) throws IOException, ClassNotFoundException {
            s.defaultReadObject();
            name=(String)s.readObject();
        }
    }
    
    image.png

    序列化总结

    Java 序列化只是针对对象的状态进行保存,至于对象中的方法,序列化不关心
    当一个父类实现了序列化,那么子类会自动实现序列化,不需要显示实现序列化接口
    当一个对象的实例变量引用了其他对象,序列化这个对象的时候会自动把引用的对象也进行序列化(实现深度克隆)
    当某个字段被申明为 transient 后,默认的序列化机制会忽略这个字段
    被申明为 transient 的字段,如果需要序列化,可以添加两个私有方法writeObject 和readObject

    分布式架构下常见序列化技术

    序列化的评价标准

    序列化后的数据小,从而使传输效率高
    其他语言可以识别和对接

    简单了解各种序列化技术

    XML 序列化框架介绍

    可读性,跨语言,但序列化之后的字节码文件较大,适合性能要求不高的系统。实现方式有 XStream 和 Java 自带的 XML 序列化和反序列化两种

    public class XStreamSerializer implements ISerializer{
        XStream xStream=new XStream(new DomDriver());
    
        @Override
        public <T> byte[] serialize(T obj) {
            return xStream.toXML(obj).getBytes();
        }
    
        @Override
        public <T> T deserialize(byte[] data, Class<T> clazz) {
            return (T)xStream.fromXML(new String(data));
        }
    }
    
    JSON 序列化框架

    可读性,跨语言且相对于xml,json序列化后的字节码文件较小,企业应用广泛
    JSON 序列化常用的开源工具有很多

    1. Jackson (https://github.com/FasterXML/jackson
    2. 阿里开源的 FastJson (https://github.com/alibaba/fastjon
    3. Google 的 GSON (https://github.com/google/gson)
      这几种 json 序列化工具中,Jackson 与 fastjson 要比 GSON 的性能要好,但是 Jackson、
      GSON 的稳定性要比 Fastjson 好。而 fastjson 的优势在于提供的 api 非常容易使用
    public class FastJsonSeriliazer implements ISerializer{
        @Override
        public <T> byte[] serialize(T obj) {
            return JSON.toJSONString(obj).getBytes();
        }
    
        @Override
        public <T> T deserialize(byte[] data, Class<T> clazz) {
            return (T)JSON.parseObject(new String(data),clazz);
        }
    }
    
    Hessian 序列化框架

    跨语言,性能更高的二进制序列化协议

    public class HessianSerializer implements ISerializer{
        @Override
        public <T> byte[] serialize(T obj) {
            ByteArrayOutputStream outputStream=new ByteArrayOutputStream();
            HessianOutput hessianOutput=new HessianOutput(outputStream);
            try {
                hessianOutput.writeObject(obj);
                return outputStream.toByteArray();
            } catch (IOException e) {
                e.printStackTrace();
            }
    
            return new byte[0];
        }
    
        @Override
        public <T> T deserialize(byte[] data, Class<T> clazz) {
            ByteArrayInputStream inputStream=new ByteArrayInputStream(data);
            HessianInput hessianInput=new HessianInput(inputStream);
            try {
                return (T)hessianInput.readObject();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return null;
        }
    }
    
    Protobuf 序列化框架

    跨语言和序列化后的字节码的文件最小,性能最高。但使用起来比较麻烦。

    Protobuf 序列化的原理

    name=mic,age=300的序列化后的结果:10 3 77 105 99 16 -84 2

    对数字的压缩
    image.png

    把300变成:-84 、2

    字符如何转化为编码

    “Mic”这个字符,需要根据 ASCII 对照表转化为数字。
    M =77、i=105、c=99
    所以结果为 77 105 99

    存储格式

    protobuf 采用 T-L-V 作为存储方式


    image.png

    tag 的计算方式是 field_number(当前字段的编号) << 3 | wire_type

    为什么空间如此小

    对值进行压缩
    没有了字段名,通过位置来知道字段名

    序列化技术的选型

    技术层面

    序列化空间开销,也就是序列化产生的结果大小,这个影响到传输的性能
    序列化过程中消耗的时长,序列化消耗时间过长影响到业务的响应时间
    序列化协议是否支持跨平台,跨语言。因为现在的架构更加灵活,如果存在异构系统通信需求,那么这个是必须要考虑的
    可扩展性/兼容性,在实际业务开发中,系统往往需要随着需求的快速迭代来实现快速更新,
    这就要求我们采用的序列化协议基于良好的可扩展性/兼容性,比如在现有的序列化数据结构中新增一个业务字段,不会影响到现有的服务
    技术的流行程度,越流行的技术意味着使用的公司多,那么很多坑都已经淌过并且得到了
    解决,技术解决方案也相对成熟学习难度和易用性

    选型建议

    对性能要求不高的场景,可以采用基于 XML 的 SOAP 协议
    对性能和间接性有比较高要求的场景,那么 Hessian、Protobuf、Thrift、Avro 都可以。
    基于前后端分离,或者独立的对外的 api 服务,选用 JSON 是比较好的,对于调试、可读性都很不错
    Avro 设计理念偏于动态类型语言,那么这类的场景使用 Avro 是可以的

    各个序列化技术的性能比较

    https://github.com/eishay/jvm-serializers/wiki

    相关文章

      网友评论

          本文标题:序列化和反序列化原理分析

          本文链接:https://www.haomeiwen.com/subject/xahejhtx.html