protobuf入門學習

     來學習一下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



發佈了14 篇原創文章 · 獲贊 4 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章