來學習一下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("[email protected]")
.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.csdn.net/xuechongyang/article/details/8659739