最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

java程序中protobuf的基本用法示例

 更新時間:2021年08月19日 09:54:14   作者:程序那些事  
這篇文章主要給大家介紹了關于java程序中protobuf的基本用法,protobuf 與json相比具有 壓縮比高 、解壓縮速度更快的優(yōu)點,本文通過示例代碼介紹的非常詳細,需要的朋友可以參考下

簡介

Protocol Buffer是google出品的一種對象序列化的方式,它的體積小傳輸快,深得大家的喜愛。protobuf是一種平臺無關和語言無關的協(xié)議,通過protobuf的定義文件,可以輕松的將其轉(zhuǎn)換成多種語言的實現(xiàn),非常方便。

今天將會給大家介紹一下,protobuf的基本使用和同java結(jié)合的具體案例。

為什么使用protobuf

我們知道數(shù)據(jù)在網(wǎng)絡傳輸中是以二進制進行的,一般我們使用字節(jié)byte來表示, 一個byte是8bits,如果要在網(wǎng)絡上中傳輸對象,一般需要將對象序列化,序列化的目的就是將對象轉(zhuǎn)換成byte數(shù)組在網(wǎng)絡中傳輸,當接收方接收到byte數(shù)組之后,再對byte數(shù)組進行反序列化,最終轉(zhuǎn)換成java中的對象。

那么將java對象序列化可能會有如下幾種方法:

  1. 使用JDK自帶的對象序列化,但是JDK自帶的序列化本身存在一些問題,并且這種序列化手段只適合在java程序之間進行傳輸,如果是非java程序,比如PHP或者GO,那么序列化就不通用了。
  2. 你還可以自定義序列化協(xié)議,這種方式的靈活程度比較高,但是不夠通用,并且實現(xiàn)起來也比較復雜,很可能出現(xiàn)意想不到的問題。
  3. 將數(shù)據(jù)轉(zhuǎn)換成為XML或者JSON進行傳輸。XML和JSON的好處在于他們都有可以區(qū)分對象的起始符號,通過判斷這些符號的位置就可以讀取到完整的對象。但是不管是XML還是JSON的缺點都是轉(zhuǎn)換成的數(shù)據(jù)比較大。在反序列化的時候?qū)Y源的消耗也比較多。

所以我們需要一種新的序列化的方法,這就是protobuf,它是一種靈活、高效、自動化的解決方案。

通過編寫一個.proto的數(shù)據(jù)結(jié)構定義文件,然后調(diào)用protobuf的編譯器,就會生成對應的類,該類以高效的二進制格式實現(xiàn)protobuf數(shù)據(jù)的自動編碼和解析。 生成的類為定義文件中的數(shù)據(jù)字段提供了getter和setter方法,并提供了讀寫的處理細節(jié)。 重要的是,protobuf可以向前兼容,也就是說老的二進制代碼也可以使用最新的協(xié)議進行讀取。

定義.proto文件

.proto文件中定義的是你將要序列化的消息對象。我們來一個最基本的student.proto文件,這個文件定義了student這個對象中最基本的屬性。

先看一個比較簡單的.proto文件:

syntax = "proto3";

package com.flydean;

option java_multiple_files = true;
option java_package = "com.flydean.tutorial.protos";
option java_outer_classname = "StudentListProtos";

message Student {
  optional string name = 1;
  optional int32 id = 2;
  optional string email = 3;

  enum PhoneType {
    MOBILE = 0;
    HOME = 1;
  }

  message PhoneNumber {
    optional string number = 1;
    optional PhoneType type = 2;
  }

  repeated PhoneNumber phones = 4;
}

message StudentList {
  repeated Student student = 1;
}

第一行定義的是protobuf中使用的syntax協(xié)議,默認情況下是proto2,因為目前最新的協(xié)議是proto3,所以這里我們使用proto3作為例子。

然后我們定義了所在的package,這個package是指編譯的時候生成文件的包。這是一個命名空間,雖然我們在后面定義了java_package,但是為了和非java語言中的協(xié)議相沖突,所以定義package還是非常有必要的。

然后是三個專門給java程序使用的option。java_multiple_files, java_package, 和 java_outer_classname.

其中java_multiple_files指編譯過后java文件的個數(shù),如果是true,那么將會一個java對象一個類,如果是false,那么定義的java對象將會被包含在同一個文件中。

java_package指定生成的類應該使用的Java包名稱。 如果沒有明確的指定,則會使用之前定義的package的值。

java_outer_classname選項定義將表示此文件的包裝類的類名。 如果沒有給java_outer_classname賦值,它將通過將文件名轉(zhuǎn)換為大寫駝峰來生成。 例如,默認情況下,“student.proto”將使用”Student”作為包裝類名稱。

接下來的部分是消息的定義,對于簡單類型來說可以使用bool, int32, float, double, 和 string來定義字段的類型。

上例中我們還使用了復雜的組合屬性,和嵌套類型。還定義了一個枚舉類。

上面我們?yōu)槊總€屬性值分配了ID,這個ID是二進制編碼中使用的唯一“標簽”。因為在protobuf中標記數(shù)字1-15比16以上的標記數(shù)字占用的字節(jié)空間要更少,因此作為一種優(yōu)化,通常將1-15這些標記用于常用或重復的元素,而將標記16和更高的標記用于不太常用的可選元素。

然后再來看看字段的修飾符,有三個修飾符分別是optional,repeated和required。

optional表示該字段是可選的,可以設置也可以不設置,如果沒有設置,則會使使用默認值,對于簡單類型來說,我們可以自定義默認值,如果不自定義,就會使用系統(tǒng)的默認值。對于系統(tǒng)的默認值來說,數(shù)字為0,字符串為空字符串,布爾值為false。

repeated表示該字段是可以重復的,這種重復實際上就是一種數(shù)組的結(jié)構。

required表示該字段是必須的,如果該字段沒有值,那么該字段將會被認為是沒有初始化,嘗試構建未初始化的消息將拋出 RuntimeException,解析未初始化的消息將拋出 IOException。

注意,在Proto3中不支持required字段。

編譯協(xié)議文件

定義好proto文件之后,就可以使用protoc命令對其進行編譯了。

protoc是protobuf提供的編譯器,一般情況下,可以從github的release庫中直接下載即可。如果你不想直接下載,或者官方提供的庫中并沒有你需要的版本,則可以使用源代碼直接進行編譯。

protoc的使用的命令如下:

protoc --experimental_allow_proto3_optional -I=SRC_DIR --java_out=DST_DIR $SRC_DIR/student.proto

如果編譯proto3,則需要添加–experimental_allow_proto3_optional選項。

我們運行一下上面的代碼。會發(fā)現(xiàn)在com.flydean.tutorial.protos包里面生成了5個文件。分別是:

Student.java              
StudentList.java          
StudentListOrBuilder.java 
StudentListProtos.java    
StudentOrBuilder.java

其中StudentListOrBuilder和StudentOrBuilder是兩個接口,Student和StudentList是這兩個類的實現(xiàn)。

詳解生成的文件

在proto文件中,我們主要定義了兩個類Student和StudentList, 他們中定義了一個內(nèi)部類Builder,以Student為例,看下這個兩個類的定義:

public final class Student extends
    com.google.protobuf.GeneratedMessageV3 implements
    StudentOrBuilder

  public static final class Builder extends
      com.google.protobuf.GeneratedMessageV3.Builder<Builder> implements
      com.flydean.tutorial.protos.StudentOrBuilder

可以看到他們實現(xiàn)的接口都是一樣的,表示他們可能提供了相同的功能。實際上Builder是對消息的一個封裝器,所有對Student的操作都可以由Builder來完成。

對于Student中的字段來說,Student類只有這些字段的get方法,而Builder中同時有get和set方法。

對于Student來說,對于字段的方法有:

// required string name = 1;
public boolean hasName();
public String getName();

// required int32 id = 2;
public boolean hasId();
public int getId();

// optional string email = 3;
public boolean hasEmail();
public String getEmail();

// repeated .tutorial.Person.PhoneNumber phones = 4;
public List<PhoneNumber> getPhonesList();
public int getPhonesCount();
public PhoneNumber getPhones(int index);

對于Builder來說,每個屬性多了兩個方法:

// required string name = 1;
public boolean hasName();
public java.lang.String getName();
public Builder setName(String value);
public Builder clearName();

// required int32 id = 2;
public boolean hasId();
public int getId();
public Builder setId(int value);
public Builder clearId();

// optional string email = 3;
public boolean hasEmail();
public String getEmail();
public Builder setEmail(String value);
public Builder clearEmail();

// repeated .tutorial.Person.PhoneNumber phones = 4;
public List<PhoneNumber> getPhonesList();
public int getPhonesCount();
public PhoneNumber getPhones(int index);
public Builder setPhones(int index, PhoneNumber value);
public Builder addPhones(PhoneNumber value);
public Builder addAllPhones(Iterable<PhoneNumber> value);
public Builder clearPhones();

多出的兩個方法是set和clear方法。clear是清空字段的內(nèi)容,讓其變回初始狀態(tài)。

我們還定義了一個枚舉類PhoneType:

  public enum PhoneType
      implements com.google.protobuf.ProtocolMessageEnum

這個類的實現(xiàn)和普通的枚舉類沒太大區(qū)別。

Builders 和 Messages

如上一節(jié)所示,Message對應的類只有get和has方法,所以它是不可以變的,消息對象一旦被構造,就不能被修改。要構建消息,必須首先構建一個構建器,將要設置的任何字段設置為你選擇的值,然后調(diào)用構建器的 build()方法。

每次調(diào)用Builder的方法都會返回一個新的Builder,當然這個返回的Builder和原來的Builder是同一個,返回Builder只是為了方便進行代碼的連寫。

下面的代碼是如何創(chuàng)建一個Student實例:

        Student xiaoming =
                Student.newBuilder()
                        .setId(1234)
                        .setName("小明")
                        .setEmail("flydean@163.com")
                        .addPhones(
                                Student.PhoneNumber.newBuilder()
                                        .setNumber("010-1234567")
                                        .setType(Student.PhoneType.HOME))
                        .build();

Student中提供了一些常用的方法,如isInitialized()檢測是否所有必須的字段都設置完畢。toString()將對象轉(zhuǎn)換成為字符串。使用它的Builder還可以調(diào)用clear()用來清除已設置的狀態(tài),mergeFrom(Message other)用來對對象進行合并。

序列化和反序列化

生成的對象中提供了序列化和反序列化方法,我們只需要在需要的時候?qū)ζ溥M行調(diào)用即可:

  • byte[] toByteArray();: 序列化消息并返回一個包含其原始字節(jié)的字節(jié)數(shù)組。
  • static Person parseFrom(byte[] data);: 從給定的字節(jié)數(shù)組中解析一條消息。
  • void writeTo(OutputStream output);: 序列化消息并將其寫入 OutputStream.
  • static Person parseFrom(InputStream input);: 從一個消息中讀取并解析消息 InputStream.

通過使用上面的方法,可以很方便的將對象進行序列化和反序列化。

協(xié)議擴展

我們在定義好proto之后,假如后續(xù)還希望對其進行修改,那么我們希望新的協(xié)議對歷史數(shù)據(jù)是兼容的。那么我們需要考慮下面幾點:

  1. 不能更改現(xiàn)有字段的ID編號。
  2. 不能添加和刪除任何必填字段。
  3. 可以 刪除可選或重復的字段。
  4. 可以 添加新的可選字段或重復字段,但您必須使用新的ID編號。

總結(jié)

好了,protocol buf的基本用法就介紹到這里,下一篇文章我們會更加詳細的介紹proto協(xié)議的具體內(nèi)容,敬請期待。
本文的例子可以參考:learn-java-base-9-to-20

到此這篇關于java程序中protobuf的基本用法的文章就介紹到這了,更多相關java中protobuf用法內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • 關于SHA算法原理與常用實現(xiàn)方式

    關于SHA算法原理與常用實現(xiàn)方式

    這篇文章主要介紹了關于SHA算法原理與常用實現(xiàn)方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-08-08
  • PowerJob的UserService工作流程源碼解讀

    PowerJob的UserService工作流程源碼解讀

    這篇文章主要介紹了PowerJob的UserService工作流程源碼解讀,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2024-01-01
  • Java實現(xiàn)對比兩個實體類字段變化的示例詳解

    Java實現(xiàn)對比兩個實體類字段變化的示例詳解

    我們在工作中,可能會在日志中記錄數(shù)據(jù)的變化情況或者在公共處理的數(shù)據(jù)增加一個日志頁面,我們可以根據(jù)CompareUtils工具類比較數(shù)據(jù)前后發(fā)生了怎樣的變化,下面我們就來看看具體實現(xiàn)吧
    2024-03-03
  • SpringBoot超詳細深入講解底層原理

    SpringBoot超詳細深入講解底層原理

    我們知道springboot內(nèi)部是通過spring框架內(nèi)嵌Tomcat實現(xiàn)的,當然也可以內(nèi)嵌jetty,undertow等等web框架;另外springboot還有一個特別重要的功能就是自動裝配,這又是如何實現(xiàn)的呢
    2022-07-07
  • 使用React和Java實現(xiàn)文本摘要小工具

    使用React和Java實現(xiàn)文本摘要小工具

    本文將詳細介紹如何使用 React 和 Java 搭建一個小型文本摘要工具,并基于 Hugging Face 提供的 API 來實現(xiàn)智能摘要功能,感興趣的可以了解下
    2024-11-11
  • eclipse 安裝lombok插件

    eclipse 安裝lombok插件

    這篇文章主要介紹了eclipse 安裝lombok插件的詳細步驟,非常不錯,具有一定的參考借鑒價值,需要的朋友可以參考下
    2018-07-07
  • Java中的三種校驗注解的使用(@Valid,@Validated和@PathVariable)

    Java中的三種校驗注解的使用(@Valid,@Validated和@PathVariable)

    本文主要介紹了Java中的三種校驗注解的使用(@Valid,@Validated和@PathVariable),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2022-04-04
  • Java中啟動jar包命令舉例詳解

    Java中啟動jar包命令舉例詳解

    這篇文章主要介紹了Java中啟動jar包命令的相關資料,文中介紹了在Windows和Linux環(huán)境下啟動和運行Java程序的方法,包括使用`java?-jar`和`javaw`命令啟動,以及如何在后臺運行程序、重定向輸出和錯誤信息、以及如何停止程序,需要的朋友可以參考下
    2024-12-12
  • JavaWeb實現(xiàn)文件上傳與下載的方法

    JavaWeb實現(xiàn)文件上傳與下載的方法

    這篇文章主要介紹了JavaWeb實現(xiàn)文件上傳與下載的方法的相關資料,需要的朋友可以參考下
    2016-01-01
  • Spring 使用注解方式進行事務管理配置方式

    Spring 使用注解方式進行事務管理配置方式

    本篇文章主要介紹了Spring 使用注解方式進行事務管理配置方式,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-04-04

最新評論

青岛市| 龙门县| 伊通| 古浪县| 宣汉县| 北京市| 中牟县| 盘山县| 玉林市| 陈巴尔虎旗| 罗山县| 金昌市| 西丰县| 洪洞县| 新巴尔虎左旗| 龙海市| 维西| 获嘉县| 安岳县| 华坪县| 阳曲县| 综艺| 精河县| 平塘县| 连州市| 丹东市| 无极县| 丽江市| 克东县| 五莲县| 南开区| 札达县| 巴中市| 安吉县| 佛学| 通城县| 集安市| 上林县| 南川市| 长兴县| 施秉县|