IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> 常见的序列化框架及Protobuf原理,让阿里面试官都赞同不已的Spring解读 -> 正文阅读

[Java知识库]常见的序列化框架及Protobuf原理,让阿里面试官都赞同不已的Spring解读

Kyro序列化是主流的比较成熟的序列化方案之一,目前广泛使用在大数据组件中,比如Hive、Storm等,性能比起Hessian还要优越,但是缺陷较明显,不支持跨语言交互,在dubbo2.6.x版本开始已经加入了Kyro序列化的支持

Protobuf序列化

Protobuf是谷歌提出的序列化方案,不同的是此方案独立于语言、平台,谷歌提供了多个语言如java、c、go、python等语言的实现,也提供了多平台的库文件支持,使用比较广泛,优点在于性能开销很小,压缩率很高,但是缺陷也很明显,可读性很差,并且protobuf需要使用特定语言的库进行翻译转换,使用起来较为麻烦

Protobuf序列化的使用

首先现在使用Protobuf,有手动编译和maven依赖jar两种方案,实际开发中我们一般使用maven坐标引入jar,坐标如下:

com.dyuproject.protostuff protostuff-core 1.0.8 com.dyuproject.protostuff protostuff-runtime 1.0.8

编写一个便捷的序列化转换工具类:

package com.demo.utils;

import com.dyuproject.protostuff.LinkedBuffer;
import com.dyuproject.protostuff.ProtobufIOUtil;
import com.dyuproject.protostuff.runtime.RuntimeSchema;

public class SerializeUtils{
/**
*序列化方法
/
public static byte[] serialize(T t,Class clazz) {
return ProtobufIOUtil.toByteArray(t, RuntimeSchema.createFrom(clazz),
LinkedBuffer.allocate(LinkedBuffer.DEFAULT_BUFFER_SIZE));
}
/

**反序列化方法
*/
public static T deSerialize(byte[] data,Class clazz) {
RuntimeSchema runtimeSchema = RuntimeSchema.createFrom(clazz);
T t = runtimeSchema.newMessage();
ProtobufIOUtil.mergeFrom(data, t, runtimeSchema);
return t;
}

使用的时候直接使用工具类进行自动的转换传输即可

注:使用的时候注意jdk版本和jar版本的兼容问题,并且需要序列化的实体并不需要实现Serializable 接口

当然,我们接下来手动编译protobuf使用,了解下protobuf的语法以及原理

手动编译Protobuf

手动编译protobuf我们需要一个Protobuf编译器的支持,这里推荐直接点击地址,在github上下载:

https://github.com/google/protobuf/releases

或者直接百度云:http://pan.baidu.com/s/1gefsM9X 下载,这里博主选择直接百度云集成的环境下载

1:解压protoc-3.0.0-beta-2-win32会得到一个protoc.exe的文件.

2:解压protobuf-3.0.0-beta-2.(3.0.0-beta是版本号,可能会有所不同)

3.将protoc.exe文件放到2步骤解压后文件夹java/src/这个目录里面(src里面,不是跟src并级)

4.WINDOS+R 输入cmd命令并切换至3步骤的src目录的上级目录,就是java目录下会发现这个目录有个POM文件,使用maven编译命令编译(mvn install),然后会在java目录下生成target以及一个jar。OK到目前位置,安装算完成了

接下来是编译环节,将上面生成的那个jar和一开始的那个exe文件放到需要编译文件的同一目录下 ,使用编译指令(cmd):

protoc --java_out=xxx/xxx.proto

如果出现:Missing input file错误,那么就使用 以下指令:

protoc xxx/xxx.proto --java_out=./

接下来,我们开始编写一个protobuf的简单demo,后缀为proto,代码如下:

syntax=“proto2”;
package com.demo.serial;
option java_package = “com.demo.serial”;
option java_outer_classname=“UserProtos”;
message User {
required string name=1;
required int32 age=2;
}

首先我们先看看上面编写的内容分别代表什么意思:

syntax=“proto2”;

这里指定了protobuf编译的版本,目前主流为proto2,当然也有不少选择最新的proto3版本,而每个大版本之间的差异还是很大的,具体区别参见官方说明:https://developers.google.com/protocol-buffers/docs/proto3

接着是:

option java_package = “com.demo.serial”

这里指定的是上一行我们设置的package对应java文件里面的package名称

option java_outer_classname=“UserProtos”

这里指定了如果编译完毕生成的java类的名称

message User

这里的message代表给User类指定对应属性类型

required string name=1

这里出现了一个特殊的修饰符类型required,在protobuf中,有如下几种修饰符:

  • required: 格式良好的 message 必须包含该字段一次。
  • optional: 格式良好的 message 可以包含该字段零次或一次(不超过一次)。
  • repeated: 该字段可以在格式良好的消息中重复任意多次(包括零)。其中重复值的顺序会被保留。

注意:在proto3版本中,为了兼容性考虑,required修饰符已经取消

完成这些以后,我们使用指令:

protoc --java_out=xxx/xxx.proto

生成protobuf转换后的实体类,然后我们在pom中引入:

com.google.protobuf protobuf.java 3.7.0

然后进行序列化:

UserProtos.User user=UserProtos.User.newBuilder().setAge(300).setName(“Mic”).build();
byte[] bytes=user.toByteArray();
for(byte bt:bytes){
System.out.print(bt+" ");
}

我们将这个结果打印出来的字节如下:

10 3 77 105 99 16 -84 2

可以看出来序列化的数值看不明白,但是的确字节数很小,说明protobuf进行了算法压缩,那么我们就要了解下protobuf压缩算法相关的详细操作,首先我们要知道protobuf的type对应的各个语言的类型:

.proto TypeNotesC++ TypeJava TypePython Type[2]Go Type
doubledoubledoublefloat*float64
floatfloatfloatfloat*float32
int32使用可变长度编码。编码负数的效率低 - 如果你的字段可能有负值,请改用 sint32int32intint*int32
int64使用可变长度编码。编码负数的效率低 - 如果你的字段可能有负值,请改用 sint64int64longint/long[3]*int64
uint32使用可变长度编码uint32int[1]int/long[3]*uint32
uint64使用可变长度编码uint64long[1]int/long[3]*uint64
sint32使用可变长度编码。有符号的 int 值。这些比常规 int32 对负数能更有效地编码int32intint*int32
sint64使用可变长度编码。有符号的 int 值。这些比常规 int64 对负数能更有效地编码int64longint/long[3]*int64
fixed32总是四个字节。如果值通常大于 228,则比 uint32 更有效。uint32int[1]int/long[3]*uint32
fixed64总是八个字节。如果值通常大于 256,则比 uint64 更有效。uint64long[1]int/long[3]*uint64
sfixed32总是四个字节int32intint*int32
sfixed64总是八个字节int64longint/long[3]*int64
boolboolbooleanbool*bool
string字符串必须始终包含 UTF-8 编码或 7 位 ASCII 文本stringStringstr/unicode[4]*string
bytes可以包含任意字节序列stringByteStringstr[]byte

Protobuf序列化的原理分析

了解了Protobuf的type转换的格式以后,我们再来看,Protobuf的存储格式,Protobuf采用了T-L-V的存储格式存储数据,其中的T代表tag,即key,L则是length,代表当前存储的类型的数据长度,当是数值类型的时候L被忽略,V代表value,即存入的值,protobuf会将每一个key根据不同的类型对应的序列化算法进行序列化,然后按照keyvaluekeyvalue的格式存储,其中key的type类型与对应的压缩算法关系如下:

| write_type | 编码方式 | type | 存储方式 |

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2021-10-22 10:49:50  更:2021-10-22 10:51:16 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 21:51:49-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码