知行合一
Github
顺翔的技术驿站
顺翔的技术驿站
  • README
  • ABOUTME
  • Computer Science
    • 数据结构与算法
      • 位运算以及位图
      • 随机数
      • 递归
      • 经典排序算法
      • 经典查找算法
      • 数组和动态数组
      • 链表
      • 栈和队列
      • 树
      • 哈希表
    • 计算机网络
      • 物理层
      • 数据链路层
      • 网络层
        • TCP
      • 运输层
      • 应用层
      • HTTP
        • HTTPS的原理
        • DNS详解
        • file协议
        • 邮件协议
    • 设计模式
      • 单例模式
      • 建造者模式
      • 原型模式
      • 工厂模式
      • 享元模式
      • 代理模式
      • 装饰者模式
      • 桥接模式
      • 适配器模式
      • 外观模式
      • 组合模式
      • 事件驱动
      • 有限状态机
      • 备忘录模式
      • 模板方法模式
      • 策略模式
      • 迭代器模式
      • 命令模式
      • 解释器模式
    • 加密与解密
      • 数字证书原理
      • cfssl
  • Programming Language
    • 编程语言学习要素
    • Java
      • 集合
        • List
          • ArrayList
          • Vector
          • Stack
          • LinkedList
        • Iterator
        • Set
          • HashSet
          • TreeSet
        • Map
          • HashMap
          • HashTable
          • TreeMap
          • LinkedHashMap
      • 常用API
        • 日期时间处理
        • System
        • Random
        • Arrays
        • Scanner
        • 格式化输出
      • java特性
        • java5特性
        • java8特性
        • java9特性
        • java10特性
        • java11特性
      • 并发编程
        • 线程基础
        • 线程同步:synchronized及其原理
        • 线程同步: volatile
        • 锁机制
        • 锁的分类与对应的Java实现
        • JUC:同步辅助类
        • JUC: AtomicXXX
        • 线程池
        • ThreadLocal详解
      • 测试
        • 使用JMH进行基准测试
      • JVM
        • 强引用、软引用、弱引用、虚引用
        • jvm内存模型
        • jvm优化
        • GC算法与回收器
        • 静态绑定与动态绑定
      • ORM
        • Mybatis
          • IBatis常用操作
      • Web编程
        • Servlet详解(一)
        • Servlet详解(二):request和response对象
        • Servlet详解(三):会话技术与Cookie
        • JSP详解(一):页面构成、EL表达式
        • JSP详解(二):九大内置对象
        • JavaWeb的编码问题
        • Thymeleaf
      • Velocity
      • Java日志框架总结
      • Spring
        • SpringIOC
        • SpringMVC
        • SpringBoot源码
      • 其他
        • Apache Commons Lang使用总结
        • 使用FtpClient进行ftp操作
        • Java PDF操作总结
        • Java使用zip4j进行文件压缩
        • Java解析Excel总结
    • JVM Language
      • Groovy
      • Scala
    • Kotlin
      • 变量和常量
      • 数据类型
        • 基本数据类型
        • 容器类型
        • 函数类型
        • null和null安全
      • 流程控制
      • 包
      • 面向对象
    • Golang
      • 关键字与标识符
      • 变量和常量
      • 数据类型
      • 函数
      • 常用API
        • 时间日期处理
        • 字符串操作
        • 正则表达式
      • 控制语句
      • 包package
      • 面向对象
      • 错误处理
      • 命令行编程
        • Cobra
      • 文件操作
      • 测试
      • 并发编程
        • sync包详解
      • 数据格式与编码
        • 使用encoding包操作xml
        • 使用encoding包操作json
        • 使用magiconair操作properties
        • 使用go-ini操作ini
      • 反射
      • Build Tools
        • Go Module
        • Go Vendor
      • 日志框架
        • zap日志框架
      • Web编程
        • Gin
    • JavaScript
      • 数据类型
      • ECMAScript
        • ECMAScript6
      • NodeJS
    • TypeScript
      • 变量和常量
      • 数据类型
      • 函数
      • 面向对象
      • 泛型
      • Build Tools
        • tsc编译
        • 与webpack整合
    • Python
      • BuildTools
        • requirements.txt
        • Ananconda
    • Swift
      • 变量和常量
    • Script Language
      • Regex
      • BAT
      • Shell
    • Markup Language
      • Markdown
      • Yaml
  • Build Tools
    • CMake
    • Maven
      • 搭建Nexus私服
      • maven使用场景
    • Gradle
  • Version Control
    • Git
      • Git工作流
      • Git分支管理
      • Git Stash
      • Git Commit Message规范
      • .gitttributes文件
    • SVN
  • Distributed
    • 分布式基础理论
      • 互联网架构演变
      • 架构设计思想AKF拆分原则
      • CAP理论
      • BASE理论
    • 一致性
      • 一致性模型
      • 共识算法
        • Paxos
        • Raft
        • ZAB
      • 复制
        • 主从复制
        • Quorum机制
        • Nacos Distro协议
      • 缓存一致性
        • 双写一致性
        • 多级缓存一致性
    • 事务一致性
      • Seata
      • 本地消息表实现方案
      • 关于dpad的事务问题的分析
    • IO
    • RPC协议
    • 序列化
    • Session共享
    • 分布式协调
      • Zookeeper
        • zk集群4节点搭建
    • 服务治理
      • Dubbo分布式治理
    • 分布式ID
      • 分布式ID生成策略总结
    • 分布式锁
    • 应用服务器
      • Tomcat
    • Web服务器
      • Nginx
        • Nginx的基本配置
        • ab接口压力测试工具
        • nginx模块
        • 随机访问页面
        • 替换响应内容
        • 请求限制
        • 访问控制
        • 状态监测
        • nginx应用场景
        • 代理服务
        • 负载均衡
        • 缓存
        • 静态资源服务器和动静分离
        • 附录
      • Kong
    • 缓存中间件
      • Caffeine
      • memcached
      • Redis
        • Centos下安装Redis
        • RatHat下安装Redis
    • 数据库中间件
      • ShardingSphere
      • MyCat2
    • 消息中间件
      • Kafka
      • RocketMQ
  • Microservices
    • 服务发现
      • Nacos注册中心
      • Consul
    • 配置中心
      • Apollo
    • 消息总线
    • 客户端负载均衡
    • 熔断器
    • 服务网关
    • 链路追踪
      • Skywalking
  • Domain-Specific
    • Auth
      • 有关权限设计的思考
      • 认证方式
      • JWT
    • 任务调度
      • QuartzScheduler
      • Elastic-Job
      • XXL-Job
      • PowerJob
    • 工作流
      • BPM
      • Activiti
      • Flowable
    • 规则引擎
      • Drools
  • Architect
    • DDD领域驱动设计
      • 三层架构设计
      • 四层架构设计
    • Cola
    • 代码设计与代码重构
      • 重构改变既有代码设计
      • 枚举规范化
      • 接口幂等
      • 限流
      • 历史与版本
      • 逻辑删除和唯一索引
      • 业务对象设计
    • 单元测试
      • SpringBoot单元测试实践
    • 项目管理
    • APM
      • SkyWalking
      • Arthas
    • 性能优化
      • 接口性能优化
    • 系统设计
      • 流程中台
      • 短信中台
      • 权限中台
        • 智电运维平台组织架构改造二期
  • Database
    • Oracle
      • Docker下安装oracle11g
    • IBM DB2
    • Mysql
      • 安装Mysql
      • 用户与权限管理
      • MySQL的逻辑架构
      • 存储引擎
      • 索引详解
      • MySql的列类型
      • MySql中表和列的设计
      • MySql的SQL详解
      • 锁机制
      • 事务
      • Mysql函数总结
      • MySql存储过程详解
      • MySql触发器详解
      • Mysql视图详解
      • Mysql中Sql语句的执行顺序
      • 配置MySql主从和读写分离
      • MySql的备份策略
      • MySql分库分表解决方案
      • MySql优化总结
      • MySQL实战调优
        • schema与数据类型优化
    • Mongo
  • File System
    • README
    • HDFS
    • FastDFS
    • MinIO
  • Linux
    • 常用的Linux命令
    • vim
    • Linux磁盘管理
    • Linux系统编程
    • RedHat
      • rpm包管理器具体用法
    • Ubuntu
      • Ubuntu下录制屏幕并做成gif图片
      • Ubuntu20.05LiveServe版安装
  • DevOps
    • VM
      • 新建一个新的Linux虚拟机需要配置的东西
      • VMware桥接模式配置centos
      • VMwareFusion配置Nat静态IP
    • Ansible
    • Container
      • Docker
        • Dockerfile详解
        • DockerCompose详解
      • Containerd
    • Kubernetes
      • 安装k8s
        • 使用Minikube安装k8s
        • centos7.x下使用kubeadm安装k8s1.21
        • ubuntu20下使用kubeadm安装k8s1.21
        • centos7.x下使用二进制方式安装k8s1.20
        • 使用DockerDesktop安装K8s(适用M1芯片)
      • 切换容器引擎
      • 使用k8s部署项目的流程
      • 集群维护-备份升级排错
    • Gitlab
      • GitlabCI/CD
    • CI/CD
      • ArgoCD
  • Big-Data
    • Hadoop
    • MapReduce
    • HDFS
  • Front-End
    • Android
      • Log的使用、自定义Log工具类
      • Android倒计时功能实现
      • 解决ViewDrawableLeft左侧图片大小不可控的问题
      • AndroidSQLite基本用法
      • View的生命周期
      • 工具类
      • WebView详解
      • ViewTreeObserver类监听ViewTree
      • 在onCreate中获取控件的宽高等信息的几种方法
      • View的foreground属性
        • MaterialDesign
          • BottomNavigationBar
          • CardView
          • Elevation高度、shadows阴影、clipping裁剪、tint着色
          • TouchFeedbackRipple波纹动画
      • Volley完全解析——使用、源码
      • Android围住神经猫的实现
      • LookLook剖析,架构概述——MVP、Retrofit+RxJava
      • Android性能优化之渲染
    • Browser
      • 浏览器的工作原理
    • HTML
      • DOCTYPE标签、XHTML与HTML的区别
    • CSS
      • CSS的继承性、层叠性、权重
      • CSS浮动float详解(一):标准文档流
      • CSS浮动float详解(二):使用float
      • CSS浮动float详解(三):清除浮动方案
    • Tools Lib
      • JavaScript 文件下载解决方案-download.js
      • js-url 用于url的js开源库
      • jsuri 用于操作url的js开源库
      • window offset
    • React
      • 模块化和组件
      • 组件的三大核心属性
      • 事件处理
      • 表单数据收集
      • 生命周期
      • DOM的diff算法
      • 工程化
        • 脚手架create-react-app
        • 工程结构和模块化
      • 路由
  • Design
    • 产品设计
      • 交互设计
由 GitBook 提供支持
在本页
  • 常见的序列化机制
  • Serializable
  • serialVersionUID
  • 静态变量序列化
  • transient 关键字
  • 父子类序列化问题
  • 序列化的存储规则
  • 深度克隆
  • JSON
  • Jackson
  • Fastjson
  • Gson
  • Protocol Buffer
  • protobuf性能高有两个主要原因
  • Hessian

这有帮助吗?

在GitHub上编辑
  1. Distributed

序列化

上一页RPC协议下一页Session共享

最后更新于1年前

这有帮助吗?

在前面我们已经讲了,Java分布式通讯基于Socket,使用Socket通讯必须指定以下关键点:

  • IP

  • Port

  • 通讯协议

其中很多通讯协议通常与RPC框架有关联,但是比较通用的,比如HTTP协议,这里就不再过多解释。关于通讯协议的部分,将会结合着RPC框架来进行讲解。本篇文章将会简单描述几种常用的序列化的使用方式,着重比较他们之间的序列化与反序列化效率。

通讯协议中不仅包含协议的内容,更是包含了我们通讯的数据。我们的数据在传输之前,位于Java代码中都是以JavaObject的形式表示的,因此这些数据在网络传输时,不可避免序列化、反序列化的过程。恰当的序列化方式不仅可以提高系统的性能,更是可以提高系统的安全性、通用性、强壮性,让系统易于调试和拓展。

常见的序列化机制

序列化方式,时间排序
优点
缺点
主要应用

Serializable

序列化结果大、传输效率低、不能跨语言对接

RMI

XML

通俗易懂、跨语言

序列化结果大、冗余标签多、传输效率低

WebService(SOAP)

JSON

通俗易懂、比起xml更精简,与js兼容好

序列化结果仍然很大、性能较低

HTTP Rest

Hessian

跨语言、紧凑的二进制协议、序列化速度快

序列化后的结果很大,大于Java序列化、可读性差

MessagePack

兼容 json 的数据格式、但是比JSON跟节省空间、支持多语言

序列化时间长大约是JSON的两倍

Protocol Buffer

吊打上面几个

需要预编译、安装 比较麻烦

Apache Thrift

与Protocol Buffers差不多、序列化时间要比Protocol Buffers短、反序列化时间要比PB长

Apache Avro

配置复杂

Kryo

针对Java的序列化系统

不跨语言

FST

针对Java的序列化系统

不跨语言

Serializable

Serializable 是Java自带的序列化方式,速度慢,不跨语言,唯一的优点可能就是Java自带,不需要引入任何第三方扩展。Serializable的序列化与发序列化需要借助ObjectInputStream和ObjectOutputStream,下面是代码演示:

@Test
public void testSerialize() throws Exception {
    ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("person"));
    oos.writeObject(Person.getInstance());
}

@Test
public void testDeSerialize() throws Exception {
    ObjectInputStream ois = new ObjectInputStream(new FileInputStream("person"));
    Person p = (Person) ois.readObject();
    System.out.println(p.getName());
}

serialVersionUID

凡是实现Serializable接口的类,都需要声明 serialVersionUID 来标识序列化版本号。当使用版本号1进行序列化时,只能通过相同的版本号的类进行反序列化,否则就会抛出java.io.InvalidClassException。以此保证序列化类型与反序列化类型是同一类型。

如果未指定serialiVersionUID,Java 编译器会自动对类进行摘要算法生成一个serialVersionUID,所以只要目标Java类有任何变动,得到的结果就会截然不同。

静态变量序列化

序列化并不保存静态变量的状态,所以序列化时静态变量 a 的值为2,那么反序列化时a的值不见的就是2,他的值仍然是 类.a 的值

transient 关键字

如果想要某个属性不参与序列化,可以给这个属性加上transient关键字。

父子类序列化问题

  • 如果父类没有实现序列化接口、子类实现了序列化接口,那么父类中的属性无法参与序列化

  • 如果父类实现了序列化接口,子类没有实现,子类继承父类,所以父子类属性都会参与序列化

序列化的存储规则

假设将Person p 对象序列化写入到文件p.bak中,第一次假设耗费15ms的时间写入到了磁盘中,那么第二次写入同样的p对象,此时Java发现磁盘中已经存在此序列化文件,那么Java不会覆盖文件,而是在文件尾部添加了5个字节的引用关系,从而提高了重复对象的写入效率。下面是代码示例:

@Test
public void testTwiceSerialize() throws Exception {
    Person person = Person.getInstance();

    File personFile = new File("person");

    ObjectOutputStream oos1 = new ObjectOutputStream(new FileOutputStream(personFile));
    oos1.writeObject(person);
    oos1.flush();
    System.out.println("第一次写入对象的");

    oos1.writeObject(person);
    oos1.flush();

    ObjectOutputStream oos2 = new ObjectOutputStream(new FileOutputStream("person2"));
    oos2.writeObject(person);

    // 进行字节流比对
    File person1File = new File("person1");
    File person2File = new File("person2");
    // 两次同时写入,不会覆盖,也不会完全追加,而是会在原先的基础上增加一个引用地址;原因:增加效率

    System.out.println("person1: " + person1File.length());
    System.out.println("person2: " + person2File.length());
}

深度克隆

使用Java Serializable 还可以实现深克隆,只需要保证要克隆的对象以及属性都实现了Serializable接口即可,复制出的对象与原有对象是两个对象。代码这里不再演示。

JSON

JSON序列化方式是Java应用程序中最为常用的序列化方式,与Javascript有较好的兼容性,最典型的就是用在Rest架构中。JSON序列化方式可以使用的第三方jar有很多,比如最常用的,也是SpringBoot中自带的JSON序列化方式:Jackson,以及Alibaba的用起来很方便的Fastjson,以及Android中常用的Gson。下面是三种工具的使用方式。

Jackson

感觉Jackson用起来不是很方便,使用Jackson需要创建一些前置对象,下面是他最简单的序列化反序列化方式:

// 序列化
ObjectMapper mapper = new ObjectMapper();
mapper.writeValueAsBytes(data);

// 反序列化
Person p = mapper.readValue(writeBytes, Person.class);

Fastjson

Fastjson是开发中公司用的较多的JSON框架,用起来比较方便,而且速度也很快,下面是他的示例代码:

// 序列化
JSON.toJSONBytes(data);

// 反序列化
Person p = JSON.parseObject(bytes, Person.class);

Gson

Gson是Google的一款JSON序列化框架,使用起来也是比较方便的,笔者是很久之前还在学习Android的时候接触的,算是接触的最早的JSON框架,但是对其使用并不是很了解:

// 序列化
Gson gson = new Gson();
gson.toJson(p);

// 反序列化
Gson gson = new Gson();
Person person = gson.fromJson(json, Person.class);

Protocol Buffer

Protocal Buffer是Google提供的一种数据序列化协议,是一种轻便高效的结构化数据存储格式,适合作为数据存储或者RPC数据交换格式。可用于通讯协议、数据存储等领域的语言无关、平台无关、可扩展的序列化结构数据格式。

实现一个Protocol Buffer较为复杂,这里使用百度提供的工具包 jprotobuf:

<dependency>
    <groupId>com.baidu</groupId>
    <artifactId>jprotobuf</artifactId>
    <version>2.2.7</version>
</dependency>

代码演示:

public class Person {
    @Protobuf(fieldType = FieldType.STRING)
    private String name;
    @Protobuf(fieldType = FieldType.INT32)
    private Integer age;
    // setter / getter
}

// 序列化
Codec<Person> personCodec = ProtobufProxy.create(Person.class, false);
byte[] data = personCodec.encode(p);
// 反序列化
Person decode = personCodec.decode(data);

protobuf性能高有两个主要原因

  • 针对字节数据进行了压缩,所以生成的数据较小,所以传输效率较高

  • 针对数据进行了缓存

Hessian

Hessian序列化的方式同样是跨语言的,是一种二进制的序列化方式。值得一提的是,Hessian序列化的速度很快,但是序列化的结果所占的字节数却很大。

// 序列化
ByteArrayOutputStream os = new ByteArrayOutputStream();
HessianOutput ho = new HessianOutput(os);
ho.writeObject(p);
// 反序列化
HessianInput hi = new HessianInput(new ByteArrayInputStream(os.toByteArray()));
Person o = (Person) hi.readObject();