JAVA的JSON序列化和二进制序列化

一、前言

  最近在一个项目中因为序列化不一致问题出现了项目的卡壳。问题出现在一个后端组员修改了一个后端共享序列化类,但是测试后没有及时提交这块代码,导致其他开发成员在发序列化对象时,出现了序列化异常。
  但是在开发的时候也出现过修改bean,但是没有出现过序列化异常的问题。于是经过对比后发现出现异常的bean使用二进制序列化,无异常出现的bean使用json二进制序列化
  于是决定写一个粗劣的对比。但是推荐看看本文章的参考文章,可以学习到很多的二进制反序列化的知识点。

二、对比

1. 环境

  • JSON序列化工具:fastjson
  • 二进制序列化工具:SerializationUtils(spring uitls 提供)
  • Bean对象
@Getter
@AllArgsConstructor
@ToString
public class BinaryBean implements Serializable {

    private Integer num;

    private String string;

    private BinaryBean value;

}

@Getter
@AllArgsConstructor
@ToString
public class JsonBean {
    private Integer num;

    private String string;

    private JsonBean value;

}
  • 测试体
public static void main(String[] args) {
    // 1. 二进制
    BinaryBean binaryValue = new BinaryBean(2, "内部", null);
    BinaryBean binaryBean = new BinaryBean(1, "外部", binaryValue);
    byte[] binaryBytes = SerializationUtils.serialize(binaryBean);
    BinaryBean binaryBean2 = (BinaryBean) SerializationUtils.deserialize(binaryBytes);
    System.out.println(binaryBean2);


    // 2. JSON
    JsonBean jsonValue = new JsonBean(2, "内部", null);
    JsonBean jsonBean = new JsonBean(1, "外部", jsonValue);
    byte[] jsonBytes = JSON.toJSONString(jsonBean, SerializerFeature.WriteClassName).getBytes(StandardCharsets.UTF_8);
    JsonBean jsonBean2 = JSON.parseObject(new String(jsonBytes, StandardCharsets.UTF_8), JsonBean.class);
    System.out.println(jsonBean2);

}

2. 对比

  通过上述的使用我们会发现,json的序列化使用和二进制的序列化使用上大致上没有什么差别。基本的区别为:

  • 二进制bean需要实现二进制接口Serializable,而JSON bean并不需要。
  • JSON和二进制反序列化的实质方式不同。JSON因为存在键值对,在JAVA内部可以通过类似反射的方式执行属性匹配和实体创建;二进制反序列化的数据结构可以理解一种JAVA对象生成操作集合,JAVA通过读取这二进制流,并进行执行(个人理解)。

  当然通过第二点区别,我们可以总结出更多的不同点,比如:

  • 平台差异性。JAVA二进制只能对于JDK版本才能使用,JSON可以跨平台。因为JSON是数据格式,而二进制可以理解为操作日志。
  • 反序列化容错性。JSON反序列化,如果出现filed不存在或是修改,最差是生成的实体类的没有该字段的值,而二级制反序列化的设置就无法执行。
  • 阅读性与保密性。JSON阅读性高,二进制阅读性小。当然保密性和阅读性刚好是相反的。

三、结尾

  再说回项目出现的问题,问题很大情况下就存在因CLASS文件被修改导致二进制反序列化的执行存在问题。