Protobuf简介
Protobuf是Google开源的二进制序列化数据协议。具有语言和平台无关性,支持多种语言接口。
Protobuf的优点:
1,通用性:多种语言支持
2,速度快:较比其他序列化格式如Json,XML编解码速度更快
3,小:因为是二进制格式,所以更小
缺点:
1,没有自描述性:因为是二进制,内容经过编码
Protobuf语法
Protobuf定义的数据格式类似于Java中的entity,而且使用protoc库可以把它转化成Java的Entity。
Protobuf定义一个数据的属性,转化成的Java类会自动添加其Getter和Setter方法以及其他辅助方法。
Protobuf的一个数据类成为message
,protobuf有类似于C语言的数据类型,与其他语言的基本数据类型可以一一对应,如下:
Protobuf的数据可以设置为:required
,optional
和repeated
required是必须存在字段,optional是可选字段,可以为空;repeated是可重复字段,转化成Java是一个List,可以存放0个,1个或多个元素。
每一个字段有一个整数唯一标识,感觉就像一个map的Key值。
Protobuf支持嵌套,即message套message。
以下例子可以阐述以上的所有规则:
message SearchResponse {
message Result {
required string url = 1;
optional string title = 2;
repeated string snippets = 3;
}
repeated Result result = 1;
}
Protobuf的应用实例
举一个例子来阐述protobuf-Java从头到尾的使用过程。
首先需要下载protobuf源代码,我选择2.5.0
下载下来的源代码根据README里面的内容进行安装。进入java文件夹,java的源码是一个maven项目,根据里面的README.txt可以进行maven安装或非maven安装,安装后在target文件夹中有protobuf-java-2.5.0.jar,这就是我们在Java项目中用来序列和反序列化protobuf数据的依赖包。
使用IDE创建一个测试的MAVEN项目,目录结构如下图:
在pom.xml添加依赖:
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
<version>2.5.0</version>
</dependency>
会自动导入jar包;或者手动将上面说的protobuf-java-2.5.0.jar加到项目中。
写proto
message Person {
// ID(必需)
required int32 id = 1;
// 姓名(必需)
required string name = 2;
// email(可选)
optional string email = 3;
// 朋友(集合)
repeated string friends = 4;
}
在命令行使用protoc命令将.proto编译成java类:
protoc --java_out=$DST_DIR $SRC_DIR/Person.proto
DSTDIR是java存储的路径, SRC_DIR是proto文件所在路径。将生成的java类放到项目的java文件夹下。
创建main类
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.List;
public class Main {
public static void main(String[] args) throws IOException {
// 按照定义的数据结构,创建一个Person
PersonMsg.Person person = PersonMsg.Person.newBuilder()
.setId(1)
.setName("wayblink")
.setEmail("xxx@gmail.com")
.addFriends("Zhang 3")
.addFriends("Li 4").build();
// 将数据写到输出流,如网络输出流,这里就用ByteArrayOutputStream来代替
ByteArrayOutputStream output = new ByteArrayOutputStream();
person.writeTo(output);
// -------------- 分割线:上面是发送方,将数据序列化后发送 ---------------
byte[] byteArray = output.toByteArray();
// -------------- 分割线:下面是接收方,将数据接收后反序列化 ---------------
// 接收到流并读取,如网络输入流,这里用ByteArrayInputStream来代替
ByteArrayInputStream input = new ByteArrayInputStream(byteArray);
// 反序列化
PersonMsg.Person person2 = PersonMsg.Person.parseFrom(input);
System.out.println("ID:" + person2.getId());
System.out.println("name:" + person2.getName());
System.out.println("email:" + person2.getEmail());
System.out.println("friend:");
List<String> friends = person2.getFriendsList();
for(String friend : friends) {
System.out.println(friend);
}
}
}
Proto的序列化与反序列化方法都在这个main方法中了。
运行:
ID:1
name:wayblink
email:xxx@gmail.com
friend:
Zhang 3
Li 4