国产亚洲精品福利在线无卡一,国产精久久一区二区三区,亚洲精品无码国模,精品久久久久久无码专区不卡

當(dāng)前位置: 首頁 > news >正文

貴陽網(wǎng)站建設(shè)zbcskj重慶seo招聘

貴陽網(wǎng)站建設(shè)zbcskj,重慶seo招聘,凡科網(wǎng)站做網(wǎng)站多少錢,陜西專業(yè)網(wǎng)站建設(shè)公司文章目錄 1.認(rèn)識 ProtoBuf2. 安裝ProtoBuf3. 快速上手 ProtoBuf4. proto3 語法5. probuf 實(shí)戰(zhàn)6. 總結(jié) 1.認(rèn)識 ProtoBuf 在認(rèn)識 啥是 ProtoBuf 之前我們先來 回顧一下 (或 了解 一下 啥是 序列化) 序列化概念回顧 : 圖一 : 回顧 序列化 ,下面…

文章目錄

  • 1.認(rèn)識 ProtoBuf
  • 2. 安裝ProtoBuf
  • 3. 快速上手 ProtoBuf
  • 4. proto3 語法
  • 5. probuf 實(shí)戰(zhàn)
  • 6. 總結(jié)

1.認(rèn)識 ProtoBuf

?

在認(rèn)識 啥是 ProtoBuf 之前我們先來 回顧一下 (或 了解 一下 啥是 序列化)

?
序列化概念回顧 :

?
圖一 :

在這里插入圖片描述

?
回顧 序列化 ,下面提出一個(gè)問題 如何來實(shí)現(xiàn)序列化

?
答 : XML , JSON , ProtoBuf 等.

?
通過 如何 實(shí)現(xiàn)序列化 就引出了 ProtoBuf , 關(guān)于 ProtoBuf 其實(shí)就是 幫助我們實(shí)現(xiàn)序列化的一種手段.

?
簡單認(rèn)識了一下 ProtoBuf ,下面就來看看 ProtoBuf 的特點(diǎn) .

?
ProtoBuf 的自身特點(diǎn) :

  • 語??關(guān)、平臺?關(guān):即?ProtoBuf??持?Java、C++、Python?等多種語?,?持多個(gè)平臺。?
  • ?效:即??XML?更?、更快、更為簡單。
  • 擴(kuò)展性、兼容性好:你可以更新數(shù)據(jù)結(jié)構(gòu),?不影響和破壞原有的舊程序。

?
ProtoBuf 的使用特點(diǎn)

  • ProtoPuf 是需要依賴 通過 編譯生的 java 代碼來使用的.

?
這里 想一下 我們自己實(shí)現(xiàn)一個(gè)序列化 要如何做 (在 Java 語言下) :

在這里插入圖片描述

?
上面就是 ProtoBuf 的使用流程 ,下面在來看看 ProtoBuf 的使用特點(diǎn) : ProtoPuf 是需要依賴 通過 編譯生的 java 代碼來使用的.

?
引用 : ProtoBuf 完整流程圖

在這里插入圖片描述

?

2. 安裝ProtoBuf

?
下載地址

?
Windows環(huán)境下安裝ProtoBuf

?
圖一 :

在這里插入圖片描述

?
圖二 :

在這里插入圖片描述

?
Linux 下安裝 ProtoBuf

?
CentOs 環(huán)境

?
使用命令 : sudo yum install autoconf automake libtool curl make gcc-c++ unzip

?
圖一 :

在這里插入圖片描述

?
圖二 :

在這里插入圖片描述

# 第?步執(zhí)?autogen.sh,但如果下載的是具體的某??語?,不需要執(zhí)?這?步。
./autogen.sh# 第?步執(zhí)?configure,有兩種執(zhí)??式,任選其?即可,如下:# 1、protobuf默認(rèn)安裝在 /usr/local ?錄,lib、bin都是分散的
./configure# 2、修改安裝?錄,統(tǒng)?安裝在/usr/local/protobuf下
./configure --prefix=/usr/local/protobuf 

?
圖一 :

在這里插入圖片描述

?
圖二 :

在這里插入圖片描述

sudo vim /etc/profile# 添加內(nèi)容如下:#(動(dòng)態(tài)庫搜索路徑) 程序加載運(yùn)?期間查找動(dòng)態(tài)鏈接庫時(shí)指定除了系統(tǒng)默認(rèn)路徑之外的其他路徑
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/protobuf/lib/#(靜態(tài)庫搜索路徑) 程序編譯期間查找動(dòng)態(tài)鏈接庫時(shí)指定查找共享庫的路徑
export LIBRARY_PATH=$LIBRARY_PATH:/usr/local/protobuf/lib/#執(zhí)?程序搜索路徑
export PATH=$PATH:/usr/local/protobuf/bin/#c程序頭?件搜索路徑
export C_INCLUDE_PATH=$C_INCLUDE_PATH:/usr/local/protobuf/include/#c++程序頭?件搜索路徑
export CPLUS_INCLUDE_PATH=$CPLUS_INCLUDE_PATH:/usr/local/protobuf/include/#pkg-config 路徑
export PKG_CONFIG_PATH=/usr/local/protobuf/lib/pkgconfig/

?
最后?步,重新執(zhí)? /etc/profile ?件: source /etc/profile

?
到此 在 Linux 下 就安裝完 ProtoBuf , 下面就來學(xué)習(xí)一下如何快速上手 ProtoBuf 。

?

3. 快速上手 ProtoBuf

?
關(guān)于 快速 上手 ProtoBuf , 這里有兩個(gè)目的 :

  1. 體驗(yàn) ProtoBuf 的使用流程
  2. l了解 ProtoBuf 的基礎(chǔ)語法

?
這里來實(shí)現(xiàn) 一個(gè) 通訊錄 1.0 來 了解 ProtoBuf 的使用流程 及 ProtoBuf 的基礎(chǔ)語法.

?
需求 :

  1. 對?個(gè)聯(lián)系?的信息使? PB 進(jìn)?序列化,并將結(jié)果打印出來。
  2. 對序列化后的內(nèi)容使? PB 進(jìn)?反序列,解析出聯(lián)系信息并打印出來。
  3. 聯(lián)系?包含以下信息: 姓名、年齡。

?
在編寫代碼之前 ,我們先來下載一個(gè)插件 :

在這里插入圖片描述

?
第一步 : 創(chuàng)建一個(gè) Maven 項(xiàng)目

在這里插入圖片描述

?
2.進(jìn)入 jar 包

<!-- protobuf ?持 Java 核?包 -->
<dependency><groupId>com.google.protobuf</groupId><artifactId>protobuf-java</artifactId><version>${protobuf.version}</version>
</dependency>

?
注意 : 這里 使用的 jar 包 版本 需要和我們安裝的 protobuf 版本一致 ,如 文章中使用的 3.21.11

在這里插入圖片描述

?
3.創(chuàng)建 對應(yīng)的包 和 文件

在這里插入圖片描述

?

下面就來 編寫我們的代碼 , 這里先來說幾個(gè)基本的語法點(diǎn)

?
在首行指定語法版本

在這里插入圖片描述

?
添加文件選項(xiàng)

?
在 .proto 文件中 可以聲明許多選項(xiàng) 使用 option 標(biāo)注 選項(xiàng)能影響?proto?編譯器的某些處理?式。

在這里插入圖片描述

?
上面先簡單寫幾個(gè)選項(xiàng), 等后面說 proto3 的在詳細(xì)介紹

?
完成上面的準(zhǔn)本工作,下面就可以定義我們的聯(lián)系人 message .

?
關(guān)于為啥要定義消息(message) 之前是說過的 ,在 認(rèn)識ProtoBuf 中 提到過 , 這里再簡單說一說 .

消息(message): 要定義的結(jié)構(gòu)化對象,我們可以給這個(gè)結(jié)構(gòu)化對象中定義其對應(yīng)的屬性內(nèi)容。在?絡(luò)傳輸中,我們需要為傳輸雙?定制協(xié)議。
?
定制協(xié)議說?了就是定義結(jié)構(gòu)體或者結(jié)構(gòu)化數(shù)據(jù),
?
?如,tcp,udp報(bào)?就是結(jié)構(gòu)化的。再?如將數(shù)據(jù)持久化存儲(chǔ)到數(shù)據(jù)庫時(shí),會(huì)將?系列元數(shù)據(jù)統(tǒng)??對象組織起來,再進(jìn)?存儲(chǔ)
?
所以ProtoBuf就是以message的?式來?持我們定制協(xié)議字段,后期幫助我們形成類和?法來使?。
?
在通訊錄1.0中我們就需要為聯(lián)系?定義?個(gè) message。

?

定義消息字段

在message中我們可以定義其屬性字段,字段定義格式為:字段類型 字段名=字段唯?編號;

  • 字段名稱命名規(guī)范:全?寫字?,多個(gè)字?之間?_連接。
  • 字段類型分為:標(biāo)量數(shù)據(jù)類型 和 特殊類型(包括枚舉、其他消息類型等)。
    • 字段唯?編號:?來標(biāo)識字段,?旦開始使?就不能夠再改變。

?

該表格展?了定義于消息體中的標(biāo)量數(shù)據(jù)類型,以及編譯 .proto ?件之后?動(dòng)?成的類中與之對應(yīng)的字段類型。在這?展?了與 JAVA 語?對應(yīng)的類型

.proto TypeNotesJava Type
doubledouble
floatfloat
int32使?變?編碼[1]。負(fù)數(shù)的編碼效率較低?若字段可 能為負(fù)值,應(yīng)使? sint32 代替。int
int64使?變?編碼[1]。負(fù)數(shù)的編碼效率較低?若字段可 能為負(fù)值,應(yīng)使? sint64 代替。long
uint32使?變?編碼[1]。int[2]
uint64使?變?編碼[1]。long[2]
sint32使?變?編碼[1]。符號整型。負(fù)值的編碼效率?于 常規(guī)的 int32 類型。int
sint64使?變?編碼[1]。符號整型。負(fù)值的編碼效率?于 常規(guī)的 int64 類型。long
fixed32定? 4 字節(jié)。若值常?于2^28 則會(huì)? uint32 更? 效。int
fixed64定? 8 字節(jié)。若值常?于2^56 則會(huì)? uint64 更? 效。long
sfixed32定? 4 字節(jié)。int
sfixed64定? 8 字節(jié)。long
string包含 UTF-8 和 ASCII 編碼的字符串,?度不能超過 2^32 。String
bytes可包含任意的字節(jié)序列但?度不能超過 2^32 。ByteString
boolboolean

?
[1] 變?編碼是指:經(jīng)過protobuf 編碼后,原本4字節(jié)或8字節(jié)的數(shù)可能會(huì)被變?yōu)槠渌止?jié)數(shù)。

[2] 在 Java 中,?符號 32 位和?符號 64 位整數(shù)使?它們對應(yīng)的有符號整數(shù)來表?,這時(shí)第?個(gè) bit 位僅是簡單地存儲(chǔ)在符號位中。

?

簡單了解看完 標(biāo)量數(shù)據(jù)類型 ,這里需要著重 的說一下 字符唯一編號的范圍

?

1 ~ 536,870,911 (2^29 - 1) ,其中 19000 ~ 19999 不可?。
?
19000 ~ 19999 不可?是因?yàn)?#xff1a;在 Protobuf 協(xié)議的實(shí)現(xiàn)中,對這些數(shù)進(jìn)?了預(yù)留。
?
如果?要在.proto ?件中使?這些預(yù)留標(biāo)識號,例如將 name 字段的編號設(shè)置為19000,編譯時(shí)就會(huì)報(bào)警:

?

// 消息中定義了如下編號,代碼會(huì)告警:// Field numbers 19,000 through 19,999 are reserved for the protobuf implementationstring name = 19000; 

?
這里 編譯 proto 文件 還沒學(xué), 這里先簡單的 看一下 定義 編號為 19000 編譯后的錯(cuò)誤

?

在這里插入圖片描述

?
最后 值得?提的是,范圍為 1 ~ 15 的字段編號需要?個(gè)字節(jié)進(jìn)?編碼, 16 ~ 2047 內(nèi)的數(shù)字需要兩個(gè)字節(jié) 進(jìn)?編碼。編碼后的字節(jié)不僅
?
只包含了編號,還包含了字段類型。所以 1 ~ 15 要?來標(biāo)記出現(xiàn)?常頻繁的字段,要為將來有可能添加的、頻繁出現(xiàn)的字段預(yù)留?些出來

上面我們定義完 message ,相面 就來編譯 contacts.proto 文件 來生成 Java 文件

這里 編譯的方法有兩種

  1. 使用 命令行編譯
  2. 使用 maven插件編譯

這里先來看定義中 : 使用命令行編譯

在這里插入圖片描述

?
編譯命令行格式為 :

protoc [--proto_path=IMPORT_PATH] --java_out=DST_DIR path/to/file.protoprotoc 是 Protocol Buffer 提供的命令?編譯?具。--proto_path 指定 被編譯的.proto?件所在?錄,可多次指定??珊唽懗?-I IMPORT_PATH 。如不指定該參數(shù),則在當(dāng)前?錄進(jìn)?搜索。當(dāng)某個(gè).proto ?件 import 其他.proto ?件時(shí), 或需要編譯的 .proto ?件不在當(dāng)前?錄下,這時(shí)就要?-I來指定搜索?錄。--java_out= 指編譯后的?件為 JAVA ?件。OUT_DIR 編譯后?成?件的?標(biāo)路徑。path/to/file.proto 要編譯的.proto?件。

?
學(xué)習(xí)完 命令行編譯 , 在來學(xué)習(xí)一下 使用 maven 插件 編譯 .

?
關(guān)于 這種編譯?式??動(dòng)執(zhí)? protoc 命令,后?跟?堆易忘的參數(shù)要高效省心得多(每次編譯都得google 或找之前記的筆記)。

?
使用 maven 插件 編譯 只需要在pom中添加 porotbuf 編譯插件:

 <plugin><groupId>org.xolstice.maven.plugins</groupId><artifactId>protobuf-maven-plugin</artifactId><version>0.6.1</version><configuration><!-- 本地安裝的protoc.exe的?錄 --><protocExecutable>D:\JavaSE練習(xí)\protobuf\protoc-21.11-win64\bin\protoc.exe</protocExecutable><!-- proto?件放置的?錄,默認(rèn)為/src/main/proto --><protoSourceRoot>${project.basedir}/src/main/proto</protoSourceRoot><!-- ?成?件的?錄,默認(rèn)?成到target/generated-sources/protobuf/ --><outputDirectory>${project.basedir}/src/main/java</outputDirectory><!-- 是否清空?標(biāo)?錄,默認(rèn)值為true。這個(gè)最好設(shè)置為false,以免誤刪項(xiàng)??件!!! --><clearOutputDirectory>false</clearOutputDirectory></configuration></plugin>

?
補(bǔ)充 : 使用這個(gè)插件是有坑的

  1. 使用這個(gè)插件 項(xiàng)目路徑是不能帶中文的

在這里插入圖片描述

?
關(guān)于兩種編譯方式就看完了, 下面我們了解一下 編譯生成的 java 文件 和 內(nèi)容.

?
圖一 :

在這里插入圖片描述

?
圖二 :

在這里插入圖片描述

?
簡單了解完 編譯器生成的代碼, 接下來就來到大家感興趣的部分,開始寫代碼了.

在這里插入圖片描述

?
到此我們就完成了下面三點(diǎn).

  1. 對?個(gè)聯(lián)系?的信息使? PB 進(jìn)?序列化,并將結(jié)果打印出來。
  2. 對序列化后的內(nèi)容使? PB 進(jìn)?反序列,解析出聯(lián)系信息并打印出來。
  3. 聯(lián)系?包含以下信息: 姓名、年齡。

?
簡單快速上手 ProtoBuf , 下面我們來學(xué)習(xí) Proto3 語法
?

4. proto3 語法

?
關(guān)于 Proto3 語法的學(xué)習(xí),通過完成下面 幾點(diǎn)需求 來學(xué)習(xí).

  • 不再打印聯(lián)系?的序列化結(jié)果,?是將通訊錄序列化后并寫??件中。
  • 從?件中將通訊錄解析出來,并進(jìn)?打印。
  • 新增聯(lián)系?屬性,共包括:姓名、年齡、電話信息、地址、其他聯(lián)系?式、備注。

?
1.字段規(guī)則

?
消息的字段可以?下??種規(guī)則來修飾:

? singular :消息中可以包含該字段零次或?次(不超過?次) ,proto3 語法中,字段默認(rèn)使?該 規(guī)則。

? repeated :消息中可以包含該字段任意多次(包括零次),其中重復(fù)值的順序會(huì)被保留??梢岳?解為定義了?個(gè)數(shù)組。

?
演示 :

在這里插入圖片描述

?
2. 消息類型的定義與使用

?
定義 : 在單個(gè) .proto ?件中可以定義多個(gè)消息體,且?持定義嵌套類型的消息(任意多層)。每個(gè)消息體中 的字段編號可以重復(fù)。

?
圖一 :

在這里插入圖片描述

?
圖二 :

在這里插入圖片描述

?
看完上面兩個(gè)語法點(diǎn)我們就可以來完成三個(gè)需求了 :

?
圖一 :

在這里插入圖片描述

?
圖二 :

在這里插入圖片描述

?

附上代碼 :

package com.example.proto3;import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Scanner;public class TestWrite {public static void main(String[] args) throws IOException {Contacts.Builder contactsBuilder = Contacts.newBuilder();//        // 讀取本地已存在的 contacts.bin 反序列化出 通訊錄對象
//        Contacts contacts = Contacts.parseFrom(new FileInputStream(
//                "src/main/java/com/example/proto3/contacts.bin"
//        ));
//
//        // 這里向統(tǒng)通訊錄中新增一個(gè)聯(lián)系人 需要獲取到 builder .
//        contactsBuilder = contacts.toBuilder();try {contactsBuilder.mergeFrom(new FileInputStream("src/main/java/com/example/proto3/contacts.bin"));} catch (FileNotFoundException e) {System.out.println("contacts.bin not find , create new file");}// 向通訊錄中新增一個(gè)聯(lián)系人contactsBuilder.addContacts(addPeopleInfo());// 序列化通訊錄, 將結(jié)果寫入文件中FileOutputStream outputStream = new FileOutputStream("src/main/java/com/example/proto3/contacts.bin");// writeTo 方法會(huì)完成兩部操作 1. 序列化 聯(lián)系熱 2. 將序列化的結(jié)果添加到 文件中contactsBuilder.build().writeTo(outputStream);}private static PeopleInfo addPeopleInfo() {PeopleInfo.Builder builder = PeopleInfo.newBuilder();Scanner sc = new Scanner(System.in);System.out.println("------------ 新增聯(lián)系人 --------------");System.out.print("請輸入聯(lián)系人姓名: ");String name = sc.nextLine();builder.setName(name);System.out.print("請輸入聯(lián)系人年齡: ");int age = sc.nextInt();// 用戶輸入完數(shù)字后會(huì)有一個(gè)回車 這里需要使用 nextLine() 將回車讀出來sc.nextLine();builder.setAge(age);// 設(shè)置聯(lián)系人的電話信息for (int i = 0; ; i++) {// 這里 寫一個(gè)死循環(huán) ,讓用戶一直輸出 電話信息System.out.print("請輸入聯(lián)系人電話" + (i + 1) + "(只輸入回車完成電話新增): ");String number = sc.nextLine();if (number.isEmpty()) {break;}PeopleInfo.Phone.Builder phoneBuilder = PeopleInfo.Phone.newBuilder();phoneBuilder.setNumber(number);builder.addPhone(phoneBuilder);}System.out.println("------------ 添加聯(lián)系人介紹 ------------");// 通過 build 方法返回一個(gè) peopleInforeturn builder.build();}
}

?
讀取 contacts.bin 文件 ,進(jìn)行反序列操作

在這里插入圖片描述

?
到此前兩個(gè) 需求就完成了,下面我們繼續(xù)來了解 proto3的語法點(diǎn).

?
3. enum類型

?
圖一 :

在這里插入圖片描述

?
圖二 :

在這里插入圖片描述

?
簡單學(xué)習(xí)完 枚舉類型 ,下面就來通過 枚舉 類型 來完成我們的需求三 :

  • 新增聯(lián)系?屬性,共 包括:姓名、年齡、電話信息、地址、其他聯(lián)系?式、備注。

在這里插入圖片描述

枚舉類型學(xué)完,下面繼續(xù) 學(xué)習(xí) proto3的語法

?
4. Any類型

?
Any 其實(shí)是一個(gè) 消息類型, 如 : message Any , Any 是ProtoBuf 為我們定義好了的消息類型.

?
引用

字段還可以聲明為 Any 類型,可以理解為泛型類型。使?時(shí)可以在 Any 中存儲(chǔ)任意消息類型。
?
Any 類 型的字段也? repeated 來修飾。 Any 類型是 google 已經(jīng)幫我們定義好的類型,在安裝 ProtoBuf 時(shí),其中的 include ?錄下查找
?
所有 google 已經(jīng)定義好的 .proto ?件。
?
在這里插入圖片描述

?

下面來使用一下 Any 類型 :

?
圖一 :

在這里插入圖片描述

?
圖二 :

在這里插入圖片描述

?
圖三 :

在這里插入圖片描述

?

附上代碼 :

?
TestWrite

package com.example.proto3;import com.google.protobuf.Any;import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Scanner;public class TestWrite {public static void main(String[] args) throws IOException {Contacts.Builder contactsBuilder = Contacts.newBuilder();//        // 讀取本地已存在的 contacts.bin 反序列化出 通訊錄對象
//        Contacts contacts = Contacts.parseFrom(new FileInputStream(
//                "src/main/java/com/example/proto3/contacts.bin"
//        ));
//
//        // 這里向統(tǒng)通訊錄中新增一個(gè)聯(lián)系人 需要獲取到 builder .
//        contactsBuilder = contacts.toBuilder();try {contactsBuilder.mergeFrom(new FileInputStream("src/main/java/com/example/proto3/contacts.bin"));} catch (FileNotFoundException e) {System.out.println("contacts.bin not find , create new file");}// 向通訊錄中新增一個(gè)聯(lián)系人contactsBuilder.addContacts(addPeopleInfo());// 序列化通訊錄, 將結(jié)果寫入文件中FileOutputStream outputStream = new FileOutputStream("src/main/java/com/example/proto3/contacts.bin");// writeTo 方法會(huì)完成兩部操作 1. 序列化 聯(lián)系熱 2. 將序列化的結(jié)果添加到 文件中contactsBuilder.build().writeTo(outputStream);// 最后別忘記關(guān)閉流對象outputStream.close();}private static PeopleInfo addPeopleInfo() {PeopleInfo.Builder builder = PeopleInfo.newBuilder();Scanner sc = new Scanner(System.in);System.out.println("------------ 新增聯(lián)系人 --------------");System.out.print("請輸入聯(lián)系人姓名: ");String name = sc.nextLine();builder.setName(name);System.out.print("請輸入聯(lián)系人年齡: ");int age = sc.nextInt();// 用戶輸入完數(shù)字后會(huì)有一個(gè)回車 這里需要使用 nextLine() 將回車讀出來sc.nextLine();builder.setAge(age);// 設(shè)置聯(lián)系人的電話信息for (int i = 0; ; i++) {// 這里 寫一個(gè)死循環(huán) ,讓用戶一直輸出 電話信息System.out.print("請輸入聯(lián)系人電話" + (i + 1) + "(只輸入回車完成電話新增): ");String number = sc.nextLine();if (number.isEmpty()) {break;}PeopleInfo.Phone.Builder phoneBuilder = PeopleInfo.Phone.newBuilder();phoneBuilder.setNumber(number);System.out.println("請輸入此電話類型(1. 移動(dòng)電話 2. 固定電話 )");int type = sc.nextInt();// 接收回車sc.nextLine();switch (type) {case 1:phoneBuilder.setType(PeopleInfo.Phone.PhoneType.MP);break;case 2:phoneBuilder.setType(PeopleInfo.Phone.PhoneType.TEL);break;default:System.out.println("選擇錯(cuò)誤!");}builder.addPhone(phoneBuilder);}// 設(shè)置聯(lián)系人的 地址信息Address.Builder addressBuilder = Address.newBuilder();System.out.print("請輸入聯(lián)系人的家庭地址: ");String homeAddress = sc.nextLine();addressBuilder.setHomeAddress(homeAddress);System.out.print("請輸入聯(lián)系人的單位地址: ");String unitAddress = sc.nextLine();addressBuilder.setUnitAddress(unitAddress);builder.setData(Any.pack(addressBuilder.build()));System.out.println("------------ 添加聯(lián)系人介紹 ------------");// 通過 build 方法返回一個(gè) peopleInforeturn builder.build();}
}

?
TestRead

package com.example.proto3;import com.google.protobuf.InvalidProtocolBufferException;import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;public class TestRead {public static void main(String[] args) throws IOException {// 讀取文件, 將讀取的內(nèi)容進(jìn)行反序列化Contacts contacts = Contacts.parseFrom(new FileInputStream("src/main/java/com/example/proto3/contacts.bin"));// 打印printContacts(contacts);
//        System.out.println(contacts.toString());}private static void printContacts(Contacts contacts) throws InvalidProtocolBufferException {int i = 1;// 通過 getContactsList() 方法 , 獲取到每個(gè) peopleInfofor (PeopleInfo peopleInfo : contacts.getContactsList()) {System.out.println("---------- 聯(lián)系人 " + i++ + "-----------------");System.out.println("姓名: " + peopleInfo.getName());System.out.println("年齡: " + peopleInfo.getAge());int j = 1;// 聯(lián)系人的電話信息是 存在一個(gè)數(shù)組里面這里就需要 遍歷打印for (PeopleInfo.Phone phone : peopleInfo.getPhoneList()) {System.out.println("電話" + j++ + ": " + phone.getNumber()+ "  (" + phone.getType().name() + ")");}// 通過 hasData 方法 判斷 Data 中是否存放了數(shù)據(jù) , 通過 is 方法 判斷 Data 中存放的是否為 Addressif (peopleInfo.hasData() && peopleInfo.getData().is(Address.class)) {// 此時(shí)說明 有數(shù)據(jù) , 并為 Address// 在打印之前需要轉(zhuǎn)化一下Address address = peopleInfo.getData().unpack(Address.class);if (!address.getHomeAddress().isEmpty()) {System.out.println("家庭地址: " + address.getHomeAddress());}if (!address.getUnitAddress().isEmpty()) {System.out.println("單位地址: " + address.getUnitAddress());}}}}
}

?
5. oneof 類型

?
到目前為止 ,我們的通訊錄 已經(jīng)可以添加 姓名 ,年齡 , 電話信息 , 地址信息 , 下面通過 oneof 類型 再給通訊錄 添加一個(gè) 字段 如 : 其他聯(lián)系方式 (qq , wechat)

?
圖一 :

在這里插入圖片描述

?
圖二 :

在這里插入圖片描述

?
6. map類型

?
這里我們學(xué)習(xí) map 類型 ,同樣 通過 升級 通訊錄來學(xué)習(xí), 這次我們向聯(lián)系人中添加備注信息.

?
圖一 :

在這里插入圖片描述

?
圖二 :

在這里插入圖片描述

?
到此 關(guān)于 protobuf 的 大部分類型我們都看過了 ,想必大家對使用 protobuf 沒啥問題了,下面來說說 使用 protobuf 的一些坑.

?
7. 默認(rèn)值

?
反序列化消息時(shí),如果被反序列化的?進(jìn)制序列中不包含某個(gè)字段,反序列化對象中相應(yīng)字段時(shí),就 會(huì)設(shè)置為該字段的默認(rèn)值。不同的類型對應(yīng)的默認(rèn)值不同:

? 對于字符串,默認(rèn)值為空字符串。
?
? 對于字節(jié),默認(rèn)值為空字節(jié)。
?
? 對于布爾值,默認(rèn)值為 false。
?
? 對于數(shù)值類型,默認(rèn)值為 0。
?
? 對于枚舉,默認(rèn)值是第?個(gè)定義的枚舉值, 必須為 0。
?
? 對于消息字段,未設(shè)置該字段。它的取值是依賴于語?。
?
? 對于設(shè)置了 repeated 的字段的默認(rèn)值是空的( 通常是相應(yīng)語?的?個(gè)空列表 )。
?
? 對于 消息字段 、 oneof字段 和 any字段 , 都有 has ?法來檢測當(dāng)前字段是否被設(shè)置。
?
? 對于 標(biāo)量數(shù)據(jù)類型 沒有 has 方法
?
舉例 :
?
在這里插入圖片描述

?
8. 更新消息

?
這里來說說 如果我們要更新消息類型需要注意那些點(diǎn) :

?
如果現(xiàn)有的消息類型已經(jīng)不再滿?我們的需求,例如需要擴(kuò)展?個(gè)字段,在不破壞任何現(xiàn)有代碼的情 況下更新消息類型?常簡單。

?
關(guān)于 更新規(guī)則 : 這里說兩點(diǎn)

  1. 新增字段 : 注意新增的字段不和老字段沖突 : 名稱 字段號
  2. 修改老字段 :
  • 禁?修改任何已有字段的字段編號。
    ?
  • int32, uint32, int64, uint64 和 bool 是完全兼容的??梢詮倪@些類型中的?個(gè)改為另?個(gè), ?不破壞前后兼容性。若解析出來的數(shù)值與相應(yīng)的類型不匹配,可能會(huì)被截?cái)?#xff08;例如,若將 64 位整數(shù)當(dāng)做 32 位進(jìn)?讀取,它將被截?cái)酁?32 位)。
    ?
    在這里插入圖片描述

?

  • sint32 和 sint64 相互兼容但不與其他的整型兼容。
    ?

  • string 和 bytes 在合法 UTF-8 字節(jié)前提下也是兼容的。
    ?

  • bytes 包含消息編碼版本的情況下,嵌套消息與 bytes 也是兼容的。
    ?

  • fixed32 與 sfixed32 兼容, fixed64 與 sfixed64兼容。 ? enum 與 int32,uint32, int64 和 uint64 兼容(注意若值不匹配會(huì)被截?cái)?#xff09;。但要注意當(dāng)反序 列化消息時(shí)會(huì)根據(jù)語?采?不同的處理?案:例如,未識別的 proto3 枚舉類型會(huì)被保存在消息 中,但是當(dāng)消息反序列化時(shí)如何表?是依賴于編程語?的。整型字段總是會(huì)保持其的值。
    ?

  • oneof:

  • 將?個(gè)單獨(dú)的值更改為 新 oneof 類型成員之?是安全和?進(jìn)制兼容的。

  • 若確定沒有代碼?次性設(shè)置多個(gè)值那么將多個(gè)字段移??個(gè)新 oneof 類型也是可?的。

  • 將任何字段移?已存在的 oneof 類型是不安全的。

?
補(bǔ)充:若是移除?字段,要保證不再使?移除字段的字段編號。正確的做法是保留字段編號 (reserved),以確保該編號將不能被重復(fù)使?。不建議直接刪除或注釋掉字段。

?

演示 : 刪除老字段后 ,定義新字段 使用老子段的編號出現(xiàn)的問題 .

?
圖一 :

在這里插入圖片描述

TestRead :

package com.example.update.service;import com.google.protobuf.InvalidProtocolBufferException;import java.io.FileInputStream;
import java.io.IOException;public class TestRead {public static void main(String[] args) throws IOException {// 讀取文件, 將讀取的內(nèi)容進(jìn)行反序列化Contacts contacts = Contacts.parseFrom(new FileInputStream("src/main/java/com/example/proto3/contacts2.bin"));// 打印printContacts(contacts);
//        System.out.println(contacts.toString());}private static void printContacts(Contacts contacts) throws InvalidProtocolBufferException {int i = 1;// 通過 getContactsList() 方法 , 獲取到每個(gè) peopleInfofor (PeopleInfo peopleInfo : contacts.getContactsList()) {System.out.println("---------- 聯(lián)系人 " + i++ + "-----------------");System.out.println("姓名: " + peopleInfo.getName());System.out.println("年齡: " + peopleInfo.getAge());int j = 1;// 聯(lián)系人的電話信息是 存在一個(gè)數(shù)組里面這里就需要 遍歷打印for (PeopleInfo.Phone phone : peopleInfo.getPhoneList()) {System.out.println("電話" + j++ + ": " + phone.getNumber());}}}
}

?
TestWrite

package com.example.update.service;import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Scanner;public class TestWrite {public static void main(String[] args) throws IOException {Contacts.Builder contactsBuilder = Contacts.newBuilder();try {contactsBuilder.mergeFrom(new FileInputStream("src/main/java/com/example/proto3/contacts2.bin"));} catch (FileNotFoundException e) {System.out.println("contacts.bin not find , create new file");}// 向通訊錄中新增一個(gè)聯(lián)系人contactsBuilder.addContacts(addPeopleInfo());// 序列化通訊錄, 將結(jié)果寫入文件中FileOutputStream outputStream = new FileOutputStream("src/main/java/com/example/proto3/contacts2.bin");// writeTo 方法會(huì)完成兩部操作 1. 序列化 聯(lián)系熱 2. 將序列化的結(jié)果添加到 文件中contactsBuilder.build().writeTo(outputStream);// 最后別忘記關(guān)閉流對象outputStream.close();}private static PeopleInfo addPeopleInfo() {PeopleInfo.Builder builder = PeopleInfo.newBuilder();Scanner sc = new Scanner(System.in);System.out.println("------------ 新增聯(lián)系人 --------------");System.out.print("請輸入聯(lián)系人姓名: ");String name = sc.nextLine();builder.setName(name);System.out.print("請輸入聯(lián)系人年齡: ");int age = sc.nextInt();// 用戶輸入完數(shù)字后會(huì)有一個(gè)回車 這里需要使用 nextLine() 將回車讀出來sc.nextLine();builder.setAge(age);// 設(shè)置聯(lián)系人的電話信息for (int i = 0; ; i++) {// 這里 寫一個(gè)死循環(huán) ,讓用戶一直輸出 電話信息System.out.print("請輸入聯(lián)系人電話" + (i + 1) + "(只輸入回車完成電話新增): ");String number = sc.nextLine();if (number.isEmpty()) {break;}PeopleInfo.Phone.Builder phoneBuilder = PeopleInfo.Phone.newBuilder();phoneBuilder.setNumber(number);builder.addPhone(phoneBuilder);}System.out.println("------------ 添加聯(lián)系人介紹 ------------");// 通過 build 方法返回一個(gè) peopleInforeturn builder.build();}
}

?
這兩個(gè)類 相比之前 減少了一些 添加字段的操作.

在這里插入圖片描述

?
看完上面知道了 要避免使用移除后老字段的編號 ,如果 字段非常多 ,編號也分常多 ,總免有忘記刪除字段后使用過的編號

?
這里想要避免這種情況 就可以使用一個(gè) 關(guān)鍵字 : reserved , proto3提供的關(guān)鍵字.

?
演示 :

在這里插入圖片描述

?
9. 未知字段

?
在這里插入圖片描述

?
10. 前后兼容性

?
在 更新字段 規(guī)則中提到過 前后兼容性問題 ,這里 就來 具體的了解一下.

?
根據(jù)上述的例?可以得出,pb是具有向前兼容的。為了敘述?便,把增加了“??”屬性的 service 稱為“新模塊”;未做變動(dòng)的 client 稱為 “?模塊”。

? 向前兼容:?模塊能夠正確識別新模塊?成或發(fā)出的協(xié)議。這時(shí)新增加的“??”屬性會(huì)被當(dāng)作未 知字段(pb 3.5版本及之后)。

? 向后兼容:新模塊也能夠正確識別?模塊?成或發(fā)出的協(xié)議。 前后兼容的作?:當(dāng)我們維護(hù)?個(gè)很龐?的分布式系統(tǒng)時(shí),由于你?法同時(shí) 升級所有 模塊,為了保證 在升級過程中,整個(gè)系統(tǒng)能夠盡可能不受影響,就需要盡量保證通訊協(xié)議的“向后兼容”或“向前兼 容”。

?
前后兼容的作?:當(dāng)我們維護(hù)?個(gè)很龐?的分布式系統(tǒng)時(shí),由于你?法同時(shí) 升級所有 模塊,為了保證 在升級過程中,整個(gè)系統(tǒng)能夠盡可能不受影響,就需要盡量保證通訊協(xié)議的“向后兼容”或“向前兼容”。

?
11. option 選項(xiàng)

?
.proto 文件中可以聲明許多選項(xiàng),使用 option 標(biāo)注。選項(xiàng)能影響 proto 編譯器的某些處理?式。

?
關(guān)于 option 能選著的選項(xiàng) 可以在 google/protobuf/descriptor.proto 中查看.

在這里插入圖片描述

?
這里來說一說關(guān)于 java 常用的選項(xiàng)

  • java_multiple_files:編譯后?成的?件是否分為多個(gè)?件,該選項(xiàng)為?件選項(xiàng)。
  • java_package:編譯后?成?件所在的包路徑,該選項(xiàng)為?件選項(xiàng)。
  • java_outer_classname:編譯后?成的proto包裝類的類名,該選項(xiàng)為?件選項(xiàng)。
  • allow_alias : 允許將相同的常量值分配給不同的枚舉常量,?來定義別名。該選項(xiàng)為枚舉選項(xiàng)。

?

前面三個(gè) 文件級別的選項(xiàng)我們已經(jīng) 使用過 ,這里不多說 這里 主要看看 allow_alias 選項(xiàng)。

?
演示 :

在這里插入圖片描述

?
除了 列舉好了的選項(xiàng) 我們 還可以自定義選項(xiàng) , 但是 關(guān)于自定義選項(xiàng) 大部分場景是用不到的,別人定義好的就足夠用了, 這里有興趣 可以自己查看

:Language Guide (proto 2) | Protocol Buffers Documentation (protobuf.dev) 這個(gè)網(wǎng)站進(jìn)行學(xué)習(xí).

?

5. probuf 實(shí)戰(zhàn)

?
到此 我們 已經(jīng)對 proto3 語法有了一定了解 ,但是 光了解 肯定還是不行的,下面我們來簡單進(jìn)行一個(gè)實(shí)戰(zhàn) ,對 通訊錄 進(jìn)行最后一次升級 ,實(shí)現(xiàn)一個(gè)網(wǎng)絡(luò)版本的通訊錄.

?
既然是網(wǎng)絡(luò)版本的肯定是存在 客戶端 , 服務(wù)器 .

在這里插入圖片描述

?
這里來看看完成這個(gè)實(shí)戰(zhàn)的 需求 :
?
? 客?端:向服務(wù)端發(fā)送聯(lián)系?信息,并接收服務(wù)端返回的響應(yīng)。

? 服務(wù)端:接收到聯(lián)系?信息后,將結(jié)果打印出來。

? 客?端、服務(wù)端間的交互數(shù)據(jù)使? Protobuf 來完成。

?
流程圖 :

在這里插入圖片描述

?
這里 使用 maven + upd 數(shù)據(jù)報(bào)套接字 進(jìn)行 編程.

?
1.搭建客戶端服務(wù)端

這里就是網(wǎng)絡(luò)編程 使用 socket 套接字 , 如果 忘記或不清楚的話 可以看看 這篇文章 :網(wǎng)絡(luò)編程 – socket 套接字_牧…的博客-CSDN博客

?
客戶端 :

在這里插入圖片描述

package com.example.internet.client;import com.example.proto3.Address;
import com.example.proto3.PeopleInfo;import java.io.IOException;
import java.net.*;public class ContactsClient {// 這里將 客戶端的 端口號 和 IP 地址寫死 .private static SocketAddress ADDRESS = new InetSocketAddress("localhost", 8888);public static void main(String[] args) throws IOException {// 創(chuàng)建客戶端 DatagramSocketDatagramSocket socket = new DatagramSocket();// 構(gòu)造 request 請求byte[] requestData = {'h', 'e', 'l', 'l', '0'};DatagramPacket requestPacket = new DatagramPacket(requestData, requestData.length, ADDRESS);// 發(fā)送 request 數(shù)據(jù)報(bào)socket.send(requestPacket);System.out.println("發(fā)送成功!");// 獲取 響應(yīng) (response)// 創(chuàng)建 response 數(shù)據(jù)報(bào) 用于接收服務(wù)端返回的響應(yīng)byte[] udpResponse = new byte[1024];DatagramPacket responsePacket = new DatagramPacket(udpResponse, udpResponse.length);// 接收 response 數(shù)據(jù)報(bào)socket.receive(responsePacket);int length = BytesUtils.getValidLength(udpResponse);byte[] responseData = BytesUtils.subByte(udpResponse, 0, length);// 打印結(jié)果System.out.printf("接收到響應(yīng) : %s" ,new String(responseData));}
}

?
BytesUtil

package com.example.internet.client;public class BytesUtils {// 獲取 bytes 的有效長度public static int getValidLength(byte[] bytes) {int i = 0;if (null == bytes || 0 == bytes.length) {return i;}for (; i < bytes.length; i++) {if (bytes[i] == '\0') {break;}}return i;}// 截?cái)郻ytespublic static byte[] subByte(byte[] b, int off, int length) {byte[] b1 = new byte[length];// 通過 arrayCopy 進(jìn)行截?cái)?(想到與 拷貝 length 長度到新的 數(shù)組中并返回)System.arraycopy(b, off, b1, 0, length);return b1;}
}

?
服務(wù)端 :

在這里插入圖片描述

package com.example.internet.service;import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
import java.util.Arrays;public class ContactsService {//服務(wù)器socket要綁定固定的端?private static final int PORT = 8888;public static void main(String[] args) throws IOException {// 創(chuàng)建 服務(wù)端 DatagramSock 指定端口號 , 發(fā)送及接收 UPD 數(shù)據(jù)報(bào)DatagramSocket socket = new DatagramSocket(PORT);// 寫一個(gè)死循環(huán) , 用于不停接收 客戶端發(fā)送的請求while (true) {System.out.println("等待接收 UDP 數(shù)據(jù)報(bào) ...");// 創(chuàng)建 request 數(shù)據(jù)報(bào) 用于接客戶端發(fā)送來的數(shù)據(jù)byte[] udpRequest = new byte[1024];DatagramPacket requestPacket = new DatagramPacket(udpRequest, udpRequest.length);// 接收 request 數(shù)據(jù)報(bào) , 在接收到數(shù)據(jù)報(bào)之前會(huì)一直阻塞socket.receive(requestPacket);// 獲取有效的 requestint length = BytesUtils.getValidLength(udpRequest);byte[] requestData = BytesUtils.subByte(udpRequest, 0, length);System.out.println("接收到請求: " + new String(requestData));// 構(gòu)造 響應(yīng)返回給客戶端byte[] responseData = {'s', 'u', 'c', 'c', 'e', 's', 's'};// 構(gòu)造 response 數(shù)據(jù)報(bào)DatagramPacket responsePacket = new DatagramPacket(responseData, responseData.length,requestPacket.getSocketAddress());// 發(fā)送 response 數(shù)據(jù)報(bào)socket.send(responsePacket);System.out.println("發(fā)送成功!");} }
}

?

效果 :

在這里插入圖片描述

?
到此 客戶端 和 服務(wù)端就構(gòu)造好了,下面 就來用上我們的 protobuf 進(jìn)行 序列化 和 反序列化操作.

?
圖一 :

在這里插入圖片描述

?
圖二 :

在這里插入圖片描述

6. 總結(jié)

?

到此關(guān)于 protobuf 的學(xué)習(xí)就完成了, 簡單學(xué)習(xí)了一下語法 ,簡單使用了一些 api .

?
這里來通過代碼的形式來對比 驗(yàn)證 JSON 和 PB 的能力.

?
1. 序列化能力對比

?
在這?讓我們分別使? PB 與 JSON 的序列化與反序列化能?, 對值完全相同的?份結(jié)構(gòu)化數(shù)據(jù)進(jìn)? 不同次數(shù)的性能測試。

為了可讀性,下?這?份?本使? JSON 格式展?了需要被進(jìn)?測試的結(jié)構(gòu)化數(shù)據(jù)內(nèi)容:

{"age": 20,"name": "張珊","phone": [{"number": "110112119","type": 0},{"number": "110112119","type": 0},{"number": "110112119","type": 0},{"number": "110112119","type": 0},{"number": "110112119","type": 0}],"qq": "95991122","address": {"home_address": "陜西省西安市?安區(qū)","unit_address": "陜西省西安市雁塔區(qū)"},"remark": {"key1": "value1","key2": "value2","key3": "value3","key4": "value4","key5": "value5"}
}

?
提供測試用的代碼 :

package com.example.compare;import com.alibaba.fastjson2.JSON;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.protobuf.Any;
import com.google.protobuf.InvalidProtocolBufferException;import static com.example.compare.PeopleInfoForJson.Phone.PhoneType.MP;public class Compare {private static int TEST_COUNT = 100000;public static void main(String[] args) throwsInvalidProtocolBufferException, JsonProcessingException {int count = 0;byte[] pbBytes = new byte[0];String jsonStr = null;ObjectMapper objectMapper = new ObjectMapper();// ------------------------------Protobuf 序列化 -----------------------------------{PeopleInfo peopleInfo = buildPeopleInfo();count = TEST_COUNT;long stime = System.currentTimeMillis();// 序列化count次while ((count--) > 0) {pbBytes = peopleInfo.toByteArray();}long etime = System.currentTimeMillis();System.out.printf("%d次 [pb序列化]耗時(shí):%dms, 序列化后的??: %d\n",TEST_COUNT, etime - stime, pbBytes.length);}// ------------------------------Protobuf 反序列化 ---------------------------------{count = TEST_COUNT;long stime = System.currentTimeMillis();// 反序列化count次while ((count--) > 0) {PeopleInfo.parseFrom(pbBytes);}long etime = System.currentTimeMillis();System.out.printf("%d次 [pb反序列化]耗時(shí):%dms\n",TEST_COUNT, etime - stime);}// ---------------------------- fastjson2 序列化 ------------------------------------{PeopleInfoForJson peopleInfoForJson = buildPeopleInfoForJson();count = TEST_COUNT;long stime = System.currentTimeMillis();// 序列化count次while ((count--) > 0) {jsonStr = JSON.toJSONString(peopleInfoForJson);//JSON.toJSONString(peopleInfoForJson);}long etime = System.currentTimeMillis();System.out.printf("%d次 [fastjson2序列化]耗時(shí):%dms, 序列化后的??: % d\n",TEST_COUNT, etime - stime, jsonStr.length());}// --------------------------- fastjson2 反序列化 -----------------------------------{count = TEST_COUNT;long stime = System.currentTimeMillis();// 反序列化count次while ((count--) > 0) {JSON.parseObject(jsonStr, PeopleInfoForJson.class);}long etime = System.currentTimeMillis();System.out.printf("%d次 [fastjson2反序列化]耗時(shí):%dms\n",TEST_COUNT, etime - stime);}// ------------------------------jackson 序列化 ---------------------------------------{PeopleInfoForJson peopleInfoForJson = buildPeopleInfoForJson();count = TEST_COUNT;long stime = System.currentTimeMillis();// 序列化count次while ((count--) > 0) {jsonStr = objectMapper.writeValueAsString(peopleInfoForJson);}long etime = System.currentTimeMillis();System.out.printf("%d次 [jackson序列化]耗時(shí):%dms, 序列化后的??: % d\n",TEST_COUNT, etime - stime, jsonStr.length());}// ------------------------------jackson 反序列化 -------------------------------------{count = TEST_COUNT;long stime = System.currentTimeMillis();// 反序列化count次while ((count--) > 0) {objectMapper.readValue(jsonStr, PeopleInfoForJson.class);}long etime = System.currentTimeMillis();System.out.printf("%d次 [jackson反序列化]耗時(shí):%dms\n",TEST_COUNT, etime - stime);}}private static PeopleInfo buildPeopleInfo() {PeopleInfo.Builder peopleBuilder = PeopleInfo.newBuilder();peopleBuilder.setName("張珊");peopleBuilder.setAge(20);peopleBuilder.setQq("95991122");for (int i = 0; i < 5; i++) {PeopleInfo.Phone.Builder phoneBuild =PeopleInfo.Phone.newBuilder();phoneBuild.setNumber("110112119");phoneBuild.setType(PeopleInfo.Phone.PhoneType.MP);}com.example.proto3.Address.Builder addressBuilder =com.example.proto3.Address.newBuilder();addressBuilder.setHomeAddress("陜西省西安市?安區(qū)");addressBuilder.setUnitAddress("陜西省西安市雁塔區(qū)");peopleBuilder.setData(Any.pack(addressBuilder.build()));peopleBuilder.putRemark("key1", "value1");peopleBuilder.putRemark("key2", "value2");peopleBuilder.putRemark("key3", "value3");peopleBuilder.putRemark("key4", "value4");peopleBuilder.putRemark("key5", "value5");return peopleBuilder.build();}private static PeopleInfoForJson buildPeopleInfoForJson() {PeopleInfoForJson peopleInfo = new PeopleInfoForJson();peopleInfo.setName("張珊");peopleInfo.setAge(20);peopleInfo.setQq("95991122");for (int i = 0; i < 5; i++) {PeopleInfoForJson.Phone phone = new PeopleInfoForJson.Phone();phone.setNumber("110112119");phone.setType(MP);peopleInfo.getPhones().add(phone);}PeopleInfoForJson.Address address = new PeopleInfoForJson.Address();address.setHomeAddress("陜西省西安市?安區(qū)");address.setUnitAddress("陜西省西安市雁塔區(qū)");peopleInfo.setAddress(address);peopleInfo.getRemark().put("key1", "value1");peopleInfo.getRemark().put("key2", "value2");peopleInfo.getRemark().put("key3", "value3");peopleInfo.getRemark().put("key4", "value4");peopleInfo.getRemark().put("key5", "value5");return peopleInfo;}
}

?
分別對相同的結(jié)構(gòu)化數(shù)據(jù)進(jìn)? 100 、 1000 、 10000 、 100000 次的序列化與反序列化,包含:PB、fastjson2、jackson,分別獲取其耗時(shí)與序列化后的 ??。

在這里插入圖片描述

完整代碼 :

總結(jié)

序列化協(xié)議通用性格式可讀性序列化大小序列化性能適?場景
JSON通?
(json、 xml已成為多種 ?業(yè)標(biāo)準(zhǔn)的編 寫?具)
文本格式輕量
(使 ?鍵值對 ?式,壓 縮了?定 的數(shù)據(jù)空 間)
web項(xiàng)?。因?yàn)闉g覽 器對于json數(shù)據(jù)?持 ?常好,有很多內(nèi)建 的函數(shù)?持。
XML通??本格式重量(數(shù) 據(jù)冗余, 因?yàn)樾枰?成對的閉 合標(biāo)簽)XML 作為?種擴(kuò)展標(biāo) 記語?,衍?出了 HTML、RDF/RDFS, 它強(qiáng)調(diào)數(shù)據(jù)結(jié)構(gòu)化的 能?和可讀性。
ProtoBuf獨(dú)?
(Protobuf只 是Google公司 內(nèi)部的?具)
?進(jìn)制格式差(只能 反序列化 后得到真 正可讀的 數(shù)據(jù))輕量(? JSON更輕 量,傳輸 起來帶寬 和速度會(huì) 有優(yōu)化)?適合?性能,對響應(yīng) 速度有要求的數(shù)據(jù)傳 輸場景。Protobuf? XML、JSON 更?、 更快。

?結(jié):

  1. XML、JSON、ProtoBuf 都具有數(shù)據(jù)結(jié)構(gòu)化和數(shù)據(jù)序列化的能?。
  2. XML、JSON 更注重?cái)?shù)據(jù)結(jié)構(gòu)化,關(guān)注可讀性和語義表達(dá)能?。ProtoBuf 更注重?cái)?shù)據(jù)序列化,關(guān)注 效率、空間、速度,可讀性差,語義表達(dá)能?不?,為保證極致的效率,會(huì)舍棄?部分元信息。
  3. ProtoBuf 的應(yīng)用場景更為明確 , XML , JSON 的應(yīng)用場景更為豐富.
http://m.aloenet.com.cn/news/44807.html

相關(guān)文章:

  • 防城港網(wǎng)站建設(shè)搜狗搜索舊版本
  • 怎樣做某個(gè)網(wǎng)站有更新的提醒seo排名計(jì)費(fèi)系統(tǒng)
  • 寧夏建設(shè)工程招標(biāo)投標(biāo)管理中心網(wǎng)站百度推廣網(wǎng)頁版
  • 網(wǎng)站后臺樹形菜單樣式seo名詞解釋
  • 粉絲社區(qū)網(wǎng)站怎么做企業(yè)網(wǎng)絡(luò)搭建方案
  • 電影網(wǎng)站模板htmlseo互聯(lián)網(wǎng)營銷培訓(xùn)
  • 網(wǎng)站的三要素手機(jī)怎么在百度上發(fā)布信息
  • 順平網(wǎng)站建設(shè)域名比價(jià)網(wǎng)
  • 網(wǎng)站導(dǎo)航欄全屏怎么做百度點(diǎn)擊排名收費(fèi)軟件
  • 建設(shè)培訓(xùn)網(wǎng)站辦安全員c證semantics
  • 下沙做網(wǎng)站一般網(wǎng)站推廣要多少錢
  • 編程和做網(wǎng)站有關(guān)系嗎營銷軟件代理推廣
  • 仿漫畫網(wǎng)站建設(shè)定制小說網(wǎng)站系統(tǒng)源碼建設(shè)百度引擎的搜索方式是什么
  • 前端優(yōu)化網(wǎng)站天津百度搜索網(wǎng)站排名
  • 做購物網(wǎng)站多少錢3分鐘搞定網(wǎng)站seo優(yōu)化外鏈建設(shè)
  • 南京軟件開發(fā)公司有哪些網(wǎng)站關(guān)鍵詞優(yōu)化價(jià)格
  • 綿陽網(wǎng)站建設(shè)公司nba東西部最新排名
  • 廣州 網(wǎng)站建設(shè)公司小程序推廣引流
  • 酒店網(wǎng)站開發(fā)常用的seo工具推薦
  • 怎么樣檢查網(wǎng)站有沒有做全站301網(wǎng)站群發(fā)軟件
  • 柳江網(wǎng)站虛擬主機(jī)公司谷歌官方seo入門指南
  • 昆明旅游網(wǎng)頁設(shè)計(jì)成都網(wǎng)站優(yōu)化seo
  • 諸城做網(wǎng)站的公司網(wǎng)站seo推廣計(jì)劃
  • 電子商務(wù)網(wǎng)站建設(shè)應(yīng)該側(cè)重哪方面網(wǎng)站優(yōu)化方法
  • 向網(wǎng)站服務(wù)器上傳網(wǎng)頁文件下載市場營銷在線課程
  • wordpress wordpress.orgseo推廣軟
  • 網(wǎng)站建設(shè)的預(yù)算指數(shù)函數(shù)圖像
  • 太原0元網(wǎng)站建設(shè)谷歌代運(yùn)營
  • java做博客網(wǎng)站有哪些招聘網(wǎng)絡(luò)營銷推廣人員
  • 嘉興手機(jī)網(wǎng)站開發(fā)費(fèi)用b站2023年免費(fèi)入口