1. 简介:
protobuf是Google开源的一种数据传输协议,类似于XML、JSON等技术,优点是protobuf序列化和反序列化的性能非常好,灵活,高效,自动,跨平台,跨语言,最主要的是它的代码生成机制。只要写一个.proto数据文件,再用编译器编译一下,可以编译成对应语言的代码。本文基于java语言。
安装:
去这里下载对应语言的protobuf,解压。
如果你是Windows环境,则还要下载多一个东西。protobuf-2.5.0-windows.zip。
解压protobuf-2.5.0-windows.zip,把protoc.exe放在Protobuf安装目录下的src里,即可。
2. 简单实例:
1.新建maven项目,引入maven坐标:
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
<version>3.5.1</version>
</dependency>
2.新建.proto文件 ,addressBook.proto
syntax = "proto2";
option java_package = "inesv.proto";
option java_outer_classname = "AddressBookProtos";
message Person {
required string name = 1;
required int32 id = 2;
optional string email = 3;
enum PhoneType {
MOBILE = 0;
HOME = 1;
WORK = 2;
}
message PhoneNumber {
required string number = 1;
optional PhoneType type = 2 [default = HOME];
}
repeated PhoneNumber phones = 4;
}
message AddressBook {
repeated Person people = 1;
}
3.编译:
编译有两种方式:
1).直接进入proto的src目录,打cmd命令:
protoc.exe -I=proto的输入目录 --java_out=java类输出目录 proto的输入目录包括包括proto文件
2).通过java的Runtime编译:编写 GenerareClass.class(这里是处理所有.proto文件)
package inesv.proto;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class GenerareClass {
public static void main(String[] args) throws IOException {
String protoPath = System.getProperty("user.dir") + "\\src\\main\\resources\\proto";
List<String> protoFileList = new ArrayList<String>();
File f = new File(protoPath);
File fa[] = f.listFiles();
for (int i = 0; i < fa.length; i++) {
File fs = fa[i];
if (fs.isFile()) {
protoFileList.add(fs.getName());
}
}
for (String protoFile : protoFileList) {
System.out.println(protoFile);
String strCmd = "D:/file/blockChain/protobuf-java-3.5.1/protobuf-3.5.1/src/protoc.exe --java_out=../../java " + protoFile;
Runtime.getRuntime().exec(strCmd, null, new File(protoPath));
}
}
}
到这里,一个proto简单例子就完成了。接下来详细讲解。。
4.对.proto文件详解:
syntax : 指定协议版本
java_package :编译后java文件存放的包
java_outer_classname : 编译生成的java文件名
这个一个地址簿的例子,AddressBook是一个message,而地址簿中又可以嵌套其他message,
message中字段的定义格式为:
修饰符 类型 字段名 = 唯一标识;
修饰符有三种:
required – 表示消息的发送方和接受方都必须处理的字段,此修饰符应该慎用,因为这不利于后期代码的兼容性,比如我们把name字段定义为required,那么接受方必须处理这个属性,如果后期由于业务需要,name字段不要,那么所有接受方都要修改代码,而如果设置为其他修饰符,就不会有这种情况。
optional – 可选
repeated –可多选
类型有:
唯一标示:字段名后边的数值为该字段的唯一标示,不能重复.
5.序列化反序列化
package inesv.proto;
import com.google.protobuf.InvalidProtocolBufferException;
import inesv.proto.AddressBookProtos.AddressBook;
import inesv.proto.AddressBookProtos.AddressBook.Builder;
import inesv.proto.AddressBookProtos.Person;
import inesv.proto.AddressBookProtos.Person.PhoneNumber;
import inesv.proto.AddressBookProtos.Person.PhoneType;
public class protoTest {
public static void main(String[] args) throws InvalidProtocolBufferException {
Person person = Person.newBuilder()
.setId(1)
.setName("lin")
.setEmail("[email protected]")
.addPhones(PhoneNumber.newBuilder().setNumber("15218612888")
.setType(PhoneType.WORK))
.build();
AddressBook addressBook = AddressBook.newBuilder()
.addPeople(person)
.build();
//序列化之前
System.out.println("序列化之前 "+addressBook.toString());
//序列化
byte[] addressBook_se = addressBook.toByteArray();
System.out.println("序列化 " + addressBook_se);
//反序列化
AddressBook AddressBook_de = AddressBook.parseFrom(addressBook_se);
System.out.println("反序列化 " + AddressBook_de);
}
}