来学习一下protobuf。它是google出的序列化产品。性能/效率高。可以用它进行模块之间的通信。json和protobuf之间,protobuf对于数据量较大的时候传输性能明显较好。
首先要下载protoc.exe,他可以让proto文件生成java文件。proto文件中定义了一个类中的属性,类型,包名。需要用protoc.exe去生成。下文会有详细介绍。这里请下载protoc2.6.1exe。与protobuf-java-2.6.1.jar包的版本相同。这个jar包需要在maven中添加dependency。
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
<version>2.6.1</version>
</dependency>
protoc.exe的下载我是直接在csdn上下载的资源。也可以从https://github.com/google/protobuf下载,但是因为exe直接下载的地址无法访问,需要下载源码用vs编译生成。会比较麻烦。还有一个jar包,定义了序列化和反序列化的实现函数,并没有深入去看。
下面来讲解下具体的例子。
首先要写一个.proto文件。用来定义要序列类的基本信息。src/main/java文件夹下新建msg.proto
syntax="proto2";
package tutorial;
option java_package = "com.baidu.protobuf"; <span style="color:#ff0000;">生成的包名</span>
option java_outer_classname = "AddressBookProtos"; <span style="color:#ff0000;">生成的类名</span>
message Person { <span style="color:#ff6666;"> 一个类</span>
required string name = 1; <span style="color:#ff0000;">required表示要序列化的类中必须带有这个属性</span>
required int32 id = 2; <span style="color:#ff0000;">数字是序列化后二进制中唯一对应的属性,类中的各个属性对应的不同</span>
optional string email = 3; <span style="color:#ff0000;">optional和required不同,是可带可不带的意思</span>
enum PhoneType { <span style="color:#ff0000;">枚举类</span>
MOBILE = 0;
HOME = 1;
WORK = 2;
}
message PhoneNumber {
required string number = 1;
optional PhoneType type = 2 [default = HOME]; <span style="color:#ff0000;">不带的话,默认值是HOME</span>
}
repeated PhoneNumber phone = 4; <span style="color:#ff0000;">repeated代表数组,list类型</span>
}
message AddressBook {
repeated Person person = 1;
}
下面把protoc.exe也复制到这个文件夹下。用cmd进入这个文件夹。输入protoc --java_out=. msg.proto。
这个命令的用法 :protoc –java_out=源码输出路径 proto文件路径
现在发现这个文件夹下多了com.baidu.protobuf包。也有了一个类。
编写一个类进行测试
package com.baidu.test;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import com.baidu.protobuf.AddressBookProtos.AddressBook;
import com.baidu.protobuf.AddressBookProtos.Person;
public class Test {
public static void print(AddressBook addressBook) {
for(Person person : addressBook.getPersonList()) {
System.out.println("Person ID: " + person.getId());
System.out.println(" Name: " + person.getName());
if(person.hasEmail()) {
System.out.println(" E-mail address: " + person.getEmail());
}
for(Person.PhoneNumber phoneNumber : person.getPhoneList()) {
switch(phoneNumber.getType()) {
case MOBILE:
System.out.print(" Moblie phone #: ");
break;
case HOME:
System.out.print(" Home phone #: ");
break;
case WORK :
System.out.print(" Work phone #: ");
break;
}
System.out.println(phoneNumber.getNumber());
}
}
}
public void serialize() throws IOException {
Person john =
Person.newBuilder()
.setId(1234)
.setName("John Doe")
.setEmail("abc@qq.com")
.addPhone(
Person.PhoneNumber.newBuilder()
.setNumber("555-4321")
.setType(Person.PhoneType.HOME))
.build(); // 要序列化的对象,格式就是类.newBuilder().set属性.build()
AddressBook.Builder addressBook = AddressBook.newBuilder();
addressBook.addPerson(john);
//serialize to disk
FileOutputStream output = new FileOutputStream("addressbook.pbd");
addressBook.build().writeTo(output); // this function do serialization
output.close();
}
public void deserialize() throws FileNotFoundException, IOException {
AddressBook addressBook =
AddressBook.parseFrom(new FileInputStream("addressbook.pbd"));
// 这个parseFrom函数可以直接反序列化
print(addressBook);
}
public static void main(String[] args) throws IOException {
Test demo = new Test();
demo.serialize();
System.out.println("serialize to disk success!!");
System.out.println("start deserialize......");
demo.deserialize();
}
}
运行后就可以看到结果。整个项目结构为:
小结
优点:
1. 性能好/效率高。对比xml冗余信息少,解析速度更快,时间和空间开销小。
2. 代码生成简单,定义好message数据结构,使用protobuf内置编译器就能得到“包装类”代码,使用包装类用来读取message数据结构。
3. 同时支持“向前兼容”和“向后兼容”。
向前兼容:服务端方升级数据结构后,客户端能正常识别新版本数据。
向后兼容:客户端升级数据结构后,依然可以正常收取服务端的老版本数据。只需要客户端将新的属性设置为“非必填(optional)”即可。
这样可以灵活地对数据结构进行升级,而无需大规模重构代码。
4. 支持多种编程语言(官方支持C++、Java、Python;开源社区响应支持了ActionScript、C#、Lisp、Erlang、Perl、PHP、Ruby等)。使用 Google 提供的 Compiler 包,也可以开发出支持其他语言的新的编译器。
缺点:
1) 应用不够广。相比XML而言,在知名度、应用广度等方面都不如。
2) 二进制格式导致可读性差。protobuf文件传输存储是二进制格式。
3) 缺乏自描述。一般来说,XML是自描述的,而protobuf格式则不是,除非有.proto文件,否则很难看懂代码。
再贴一个protobuf与netty配合使用的博文地址。可以看下。
http://blog.youkuaiyun.com/xuechongyang/article/details/8659739