ProtoBuf的介绍以及在Java中使用protobuf将对象进行序列化与反序列化
場景
ProtoBuf簡介
protocol buffers 是一種語言無關(guān)、平臺(tái)無關(guān)、可擴(kuò)展的序列化結(jié)構(gòu)數(shù)據(jù)的方法,它可用于(數(shù)據(jù))通信協(xié)議、數(shù)據(jù)存儲(chǔ)等。
Protocol Buffers 是一種靈活,高效,自動(dòng)化機(jī)制的結(jié)構(gòu)數(shù)據(jù)序列化方法-可類比 XML,但是比 XML 更小(3 ~ 10倍)、更快(20 ~ 100倍)、更為簡單。
你可以定義數(shù)據(jù)的結(jié)構(gòu),然后使用特殊生成的源代碼輕松的在各種數(shù)據(jù)流中使用各種語言進(jìn)行編寫和讀取結(jié)構(gòu)數(shù)據(jù)。你甚至可以更新數(shù)據(jù)結(jié)構(gòu),而不破壞由舊數(shù)據(jù)結(jié)構(gòu)編譯的已部署程序。
ProtocolBuffer擁有多項(xiàng)比XML更高級(jí)的串行化結(jié)構(gòu)數(shù)據(jù)的特性,ProtocolBuffer:
·??????? 更簡單
·??????? 小3-10倍
·??????? 快20-100倍
·??????? 更少的歧義
·??????? 可以方便的生成數(shù)據(jù)存取類
怎樣使用ProtoBuf
定義proto描述文件
首先需要在一個(gè) .proto 文件中定義你需要做串行化的數(shù)據(jù)結(jié)構(gòu)信息。每個(gè)ProtocolBuffer信息是一小段邏輯記錄,包含一系列的鍵值對(duì)。這里有個(gè)非常簡單的 .proto 文件定義了個(gè)人信息:
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 phone=4; }當(dāng)然這里的protobuf的秒數(shù)文件.proto也是有版本語法限制的,比如protoBuf3中沒有required和optional。
每個(gè)消息類型擁有一個(gè)或多個(gè)特定的數(shù)字字段,每個(gè)字段擁有一個(gè)名字和一個(gè)值類型。值類型可以是數(shù)字(整數(shù)或浮點(diǎn))、布 爾型、字符串、原始字節(jié)或者其他ProtocolBuffer類型,還允許數(shù)據(jù)結(jié)構(gòu)的分級(jí)。
上面的message就類似于類,下面是屬性。
required在protobuf2代表是必填的,optional在protobuf2中代表是可選的。repeated代表重復(fù)字段,類似于list。
下面的enum代表是枚舉。
下面的message是在上面Person的里面,代表內(nèi)部類。default代表默認(rèn)值。
需要注意的是這里的=1,=2等都不是對(duì)其進(jìn)行賦值,而是對(duì)屬性做一個(gè)唯一標(biāo)志。
編譯描述文件
一旦你定義了自己的報(bào)文格式(message),你就可以運(yùn)行ProtocolBuffer編譯器,將你的 .proto 文件編譯成特定語言的類。這些類提供了簡單的方法訪問每個(gè)字段(像是 query() 和set_query()),像是訪問類的方法一樣將結(jié)構(gòu)串行化或反串行化。
編譯器下載地址:
https://github.com/protocolbuffers/protobuf/releases
選擇指定的操作系統(tǒng)的指定protobuf版本的protoc編譯器進(jìn)行下載
?
這里操作系統(tǒng)是Windows64位并且在下面要使用的protobuf的版本是3.13
所以這里下載對(duì)應(yīng)的版本
?
將其下載到電腦上某路徑下解壓
?
后續(xù)就可以使用protoc.exe對(duì)proto文件進(jìn)行編譯。
為了使用方便,這里將protoc.exe添加進(jìn)環(huán)境變量
?
然后打開cmd,輸入protoc后回車,會(huì)輸出編譯的提示命令則是成功
?
?
Java中使用ProtoBuf序列化和反序列化示例
新建項(xiàng)目并引入依賴
打開IDEA-新建一個(gè)gradle項(xiàng)目,當(dāng)然你也可以新建一個(gè)Maven項(xiàng)目。
這里以使用gradle作為依賴管理進(jìn)行示例。
新建gradle項(xiàng)目后選擇Java語言,然后添加protobuf相關(guān)的依賴。
來到Maven的中央倉庫
https://mvnrepository.com/
搜索protobuf
?
這兩個(gè)就是需要引入的依賴。
分別進(jìn)入兩個(gè)依賴中選擇跟上面的編譯的版本一致的版本
?
這里是Gradle的依賴,你也可以使用Maven并復(fù)制Maven的依賴。
?
找到IDEA中新建的gradle項(xiàng)目的build.gradle將兩個(gè)依賴添加進(jìn)去。
dependencies {compile ([group:'com.google.protobuf', name: 'protobuf-java', version: '3.13.0'],[group:'com.google.protobuf', name: 'protobuf-java-util', version: '3.13.0']) }因?yàn)樵O(shè)置了自動(dòng)導(dǎo)入,所以會(huì)在項(xiàng)目中引入Google的相關(guān)protobuf的依賴的jar包
?
編寫proto描述文件
然后在src下新建protobuf目錄,在此目錄下新建文件Student.proto
?
此時(shí)IDEA會(huì)提示,選擇Text即可。
syntax = "proto3";package com.badao.protobuf;option optimize_for =SPEED; option java_package = "com.badao.protobuf"; option java_outer_classname = "DataInfo";message Student {string name = 1;int32 age = 2;string address = 3; }然后將其內(nèi)容修改如下
這里的syntax代表使用的語法規(guī)則是protobuf3
然后下面的package是缺省時(shí)的包名,如果下面沒有設(shè)置java_package則會(huì)使用此設(shè)置,如果設(shè)置了則不會(huì)使用。
下面的是一些配置
optimize_for是文件級(jí)別的選項(xiàng),Protocol Buffer定義三種優(yōu)化級(jí)別SPEED/CODE_SIZE/LITE_RUNTIME。缺省情況下是SPEED。
SPEED: 表示生成的代碼運(yùn)行效率高,但是由此生成的代碼編譯后會(huì)占用更多的空間。
然后java_package就是配置的生成代碼的包名,
java_outer_classname選項(xiàng)表明想要生成Java類的名稱。如果在.proto文件中沒有明確的java_outer_classname定義,生成的class名稱將會(huì)根據(jù).proto文件的名稱采用駝峰式的命名方式進(jìn)行生成。如(foo_bar.proto生成的java類名為FooBar.java)。
這里配置的類名就叫DataInfo。
編譯描述文件生成代碼
在IDEA中下面的Terminal新建一個(gè)終端
?
因?yàn)橐呀?jīng)將protoc編譯命令的exe添加進(jìn)環(huán)境變量,所以這里直接使用protoc命令即可。
protoc --java_out=src/main/java src/protobuf/Student.proto這里--java_out=src/main/java就是設(shè)置的要生成代碼后存放的位置
后面跟著個(gè)空格然后跟的是 proto描述文件的位置
回車后如果沒有報(bào)錯(cuò),并且已經(jīng)在src/main/java/com/badao/protobuf下生成DataInfo類
?
則編譯成功。
對(duì)象數(shù)據(jù)的序列化與反序列化
在此包下新建一個(gè)ProtobuTest類,并編寫main方法
package com.badao.protobuf;import com.google.protobuf.InvalidProtocolBufferException;public class ProtobufTest {public static void main(String[] args) throws InvalidProtocolBufferException {DataInfo.Student student = DataInfo.Student.newBuilder().setName("公眾號(hào):霸道的程序猿").setAge(100).setAddress("中國").build();byte[] bytes = student.toByteArray();DataInfo.Student student1 = DataInfo.Student.parseFrom(bytes);System.out.println(student1.getName());System.out.println(student1.getAge());System.out.println(student1.getAddress());} }注意這里的新建對(duì)象并對(duì)屬性進(jìn)行賦值時(shí)必須采用如上這種方式
??????? DataInfo.Student student = DataInfo.Student.newBuilder().setName("公眾號(hào):霸道的程序猿").setAge(100).setAddress("中國").build();然后將對(duì)象進(jìn)行序列化為字節(jié)數(shù)組就可以通過
byte[] bytes = student.toByteArray();將字節(jié)數(shù)據(jù)反序列化為對(duì)象就可以通過
DataInfo.Student student1 = DataInfo.Student.parseFrom(bytes);然后運(yùn)行該main方法。
?
示例代碼下載
https://download.csdn.net/download/BADAO_LIUMANG_QIZHI/12858952
?
?
?
?
?
總結(jié)
以上是生活随笔為你收集整理的ProtoBuf的介绍以及在Java中使用protobuf将对象进行序列化与反序列化的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ProtoBuf在使用protoc进行编
- 下一篇: Netty中集成Protobuf实现Ja