什么是 Protobuf弃衍?
- Protobuf 是 Google 開發(fā)的一種數(shù)據(jù)交換的序列化協(xié)議肴焊,性能非常高唧瘾,大部分 IM 通訊協(xié)議都是使用它來傳輸,例如支付寶缨该、微信等 APP
安裝 Protobuf
Window 系統(tǒng)
- 下載需要的安裝包:https://github.com/google/protobuf/releases
- protoc-3.6.0-win32.zip
- protobuf-java-3.6.0.zip
- 將 protoc-3.6.0-win32.zip 中的 protoc.exe 拷貝到 c:\windows\system32 中
- 將 proto.exe 文件拷貝到解壓后的 protobuf-java-3.6.0\src 目錄中
- 在 protobuf-java-3.6.0\java 目錄下執(zhí)行 mvn package 命令(這一步相當(dāng)于安裝了)
- 執(zhí)行 protoc –-version 命令檢查是否安裝成功
MAC 系統(tǒng)
- 對于 Mac 系統(tǒng)只需要使用 brew 安裝即可
brew install protobuf
Protobuf 描述文件
更詳細(xì)的描述文件編寫可以閱讀該篇文章:https://blog.csdn.net/u011518120/article/details/54604615#ScalarValueTypes
- Protobuf 編譯器通過描述文件(.proto文件)生成對應(yīng)于語言的代碼偎行,代碼中定義了消息類型、獲取贰拿、設(shè)置蛤袒、編解碼序列化等操作。這也是為什么 Protobuf 支持跨語言傳輸膨更,因為消息所有端共用一個通用的描述文件
定義一個消息類型
- 下面 .proto 文件定義了一個 "搜索請求" 消息格式
syntax = "proto3"; // 指定使用 proto3 語法
option java_package = "com.test"; // 指定包名
option java_outer_classname = "ProtoBufTest"; // 指定類名
message SearchRequest {
string query = 1; // 指定字段類型為 string妙真,標(biāo)識號為 1
int32 page_number = 2;
int32 result_per_page = 3;
enum Corpus { // 枚舉類型
UNIVERSAL = 0; // 每個枚舉類型必須將其第一個類型映射為 0 作為默認(rèn)值
WEB = 1;
IMAGES = 2;
LOCAL = 3;
NEWS = 4;
PRODUCTS = 5;
VIDEO = 6;
}
Corpus corpus = 4;
repeated Result results = 5;
}
message Result {
...
}
- 標(biāo)識號:每個字段都有唯一的數(shù)字標(biāo)識號,需要注意的是 [1,15] 之內(nèi)的標(biāo)識在編碼時只占用 1 字節(jié)荚守,[16,2047] 之內(nèi)的占用 2 字節(jié)珍德,所以應(yīng)該對那些頻繁出現(xiàn)的消息元素預(yù)留 [1,15] 之內(nèi)的標(biāo)識號
導(dǎo)入定義
- 如果要使用的消息類型已在其它 .proto 文件中定義過,則可以通過導(dǎo)入其它 .proto 文件定義來使用它們
import "xxxx/xxx.proto";
字段類型
- 字段類型參考如下圖
Java 使用 Protobuf
- 編寫 gps_data.proto 描述文件
syntax = "proto3";
option java_package = "com.test";
option java_outer_classname = "GpsDataProto";
message gps_data {
int64 id = 1;
string terminalId = 2;
string dataTime = 3;
double lon = 4;
double lat = 5;
float speed = 6;
int32 altitude = 7;
int32 locType = 8;
int32 gpsStatus = 9;
float direction = 10;
int32 satellite = 11;
}
- 執(zhí)行下面命令編譯生成 Java 代碼
- -I 后面是 proto 文件所在目錄
- --java_out 后面是 java 文件存放地址
- 最后一行是 proto 文件名稱
protoc -I=src/main/resource/proto --java_out=src/main/java gps_data.proto
- 引入依賴
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
<version>3.5.1</version>
</dependency>
- 在代碼中使用該類
public class Main {
public static void main(String[] args) {
System.out.println("===== 構(gòu)建一個GPS模型開始 =====");
GpsDataProto.gps_data.Builder gps_builder = GpsDataProto.gps_data.newBuilder();
gps_builder.setAltitude(1);
gps_builder.setDataTime("2017-12-17 16:21:44");
gps_builder.setGpsStatus(1);
gps_builder.setLat(39.123);
gps_builder.setLon(120.112);
gps_builder.setDirection(30.2F);
gps_builder.setId(100L);
GpsDataProto.gps_data gps_data = gps_builder.build();
System.out.println(gps_data.toString());
System.out.println("===== 構(gòu)建GPS模型結(jié)束 =====");
System.out.println("===== gps Byte 開始=====");
for (byte b : gps_data.toByteArray()) {
System.out.print(b);
}
System.out.println("\n" + "bytes長度" + gps_data.toByteString().size());
System.out.println("===== gps Byte 結(jié)束 =====");
System.out.println("===== 使用gps 反序列化生成對象開始 =====");
GpsDataProto.gps_data gd = null;
try {
gd = GpsDataProto.gps_data.parseFrom(gps_data.toByteArray());
} catch (InvalidProtocolBufferException e) {
e.printStackTrace();
}
System.out.print(gd.toString());
System.out.println("===== 使用gps 反序列化生成對象結(jié)束 =====");
}
}