1. 程式人生 > 其它 >protobuf學習詳解

protobuf學習詳解

1.根據proto檔案生成 java檔案

  1. 安裝protoc命令

    下載地址:https://github.com/protocolbuffers/protobuf/releases

    如果想快捷使用,請配置相關的環境變數

  2. 執行以下命令,可以儲存為指令碼一件執行

protoc --proto_path=E:\github\java-interview\java-learn\src\main\java\com\hsm\java\serialize\protobuf --java_out=E:\github\java-interview\java-learn\src\main\java  E:\github\java-interview\java-learn\src\main\java\com\hsm\java\serialize\protobuf\*.proto
  • protoc :命令
  • --proto_path:proto檔案路徑
  • --java_out:java檔案儲存地址
  • *.proto:需要生成的檔案
  1. idea外掛

    嘗試了很多的方式,都以失敗告終。有興趣的可以自己再嘗試以下

2. 使用

  1. NettyMessageProToBuf.proto

    syntax = "proto3";
    option java_package = "com.hsm.java.serialize.protobuf";
    option java_outer_classname = "NettyMessage";
    
    message NettyMessageProToBuff{
      string requestId = 1;
      int32 msgType = 2;
      string data = 3;
    }
    

    將檔案放到目錄下,執行指令碼就可以生成對應的java檔案到目錄下

  2. 使用

    @Slf4j
    public class Main {
        public static void main(String[] args) throws InvalidProtocolBufferException {
            NettyMessage.NettyMessageProToBuff.Builder builder = NettyMessage.NettyMessageProToBuff.newBuilder();
            builder.setRequestId("q");
            builder.setMsgType(1);
            builder.setData("a");
            
            NettyMessage.NettyMessageProToBuff build = builder.build();
            log.info("build資料:{}" , build.toByteArray());
    //        NettyMessage.NettyMessageProToBuff nettyMessageProToBuff = NettyMessage.NettyMessageProToBuff.parseFrom(build.toByteArray());
            //log.info("資料:{}" , JSON.toJSONString(nettyMessageProToBuff));
    		
            //這裡和json序列化對比
            JsonData jsonData = new JsonData();
            jsonData.setRequestId("q");
            jsonData.setMsgType(1);
            jsonData.setData("a");
            log.info("Jsondata:{}" , JSON.toJSONString(jsonData).getBytes(StandardCharsets.UTF_8));
        }
    }
    

    對比資料結果:

    build資料:[10, 1, 113, 16, 1, 26, 1, 97]
    Jsondata:[123, 34, 100, 97, 116, 97, 34, 58, 34, 97, 34, 44, 34, 109, 115, 103, 84, 121, 112, 101, 34, 58, 49, 44, 34, 114, 101, 113, 117, 101, 115, 116, 73, 100, 34, 58, 34, 113, 34, 125]
    

    可以明顯看到json格式後的二進位制檔案比 protobuf檔案大很多

3. protobuf為何這麼快

參考部落格

protobuf採用編號的形式,將欄位名省去,通過編號的方式與資料一一對應。編號用tag表述

二進位制格式就是 tag|value tage|value

每個訊息項前面都會有對應的tag,才能解析對應的資料型別,表示tag的資料型別也是Varint。

  • tag的計算方式: (field_number << 3) | wire_type

每種資料型別都有對應的wire_type:

Wire Type Meaning Used For
0 Varint int32, int64, uint32, uint64, sint32, sint64, bool, enum
1 64-bit fixed64, sfixed64, double
2 Length-delimited string, bytes, embedded messages, packed repeated fields
3 Start group groups (deprecated)
4 End group groups (deprecated)
5 32-bit fixed32, sfixed32, float

比如下面資料

message NettyMessageProToBuff{
  string requestId = 1; //q
  int32 msgType = 2;//1
  string data = 3;//a
}

對應的tag分別為:

  • 1 <<<3 | 2 = 10
  • 2 <<<3 | 0 = 16
  • 3 <<<3 | 2 = 26

另外string 型別不確定字元長度,所以需要一個長度標識位,最終的結果為 build資料:[10, 1, 113, 16, 1, 26, 1, 97]