目錄
1、前言
2、Protobuf簡介
2.1、核心思想
2.2、Protobuf是如何工作的?
2.3、如何使用 Protoc 生成代碼?
3、Springboot集成
3.1、引入依賴
3.2、定義Proto文件
3.3、Protobuf生成Java代碼
3.4、配置Protobuf的序列化和反序列化
3.5、定義controller接口
3.6、訪問
4、小結
1、前言
在以往的項目中進行網絡通信和數據交換的應用場景中,最經常使用的技術便是json或xml。隨著JSON的靈活優勢,越來越多的企業選擇JSON作為數據交換的格式,目前JSON已經成為了業界的主流。JSON已經足夠好用,且能滿足相當大部分的場景。但是今天在介紹一個Google的力作protobuf作為數據交換格式。我們來看看。
2、Protobuf簡介
Github地址:GitHub - protocolbuffers/protobuf: Protocol Buffers - Google's data interchange format
官網地址:Overview | Protocol Buffers Documentation
Protobuf(Protocol Buffers)是由 Google 開發的一種輕量級、高效的數據交換格式,它被用于結構化數據的序列化、反序列化和傳輸。相比于 XML 和 JSON 等文本格式,Protobuf 具有更小的數據體積、更快的解析速度和更強的可擴展性。同時他是一種語言無關、平臺無關、可擴展的序列化格式。它使開發人員能夠在文件中定義結構化數據.proto,然后使用該文件生成可以從不同數據流寫入和讀取數據的源代碼。
2.1、核心思想
Protobuf 核心思想是使用協議來定義數據的結構和編碼方式。協議是一個文本文件,其中定義了消息的結構。消息由字段組成,每個字段都有一個名稱、類型和可選的默認值。然后使用Protobuf提供的解碼器生成對應代碼,用于序列化和反序列化數據,由于Protobuf是基于二進制編碼,因此可以跨語言使用。
Protobuf 支持以下數據類型:
- 基本類型:例如?int32、string、bool?等
- 復合類型:例如?message、enum?等
2.2、Protobuf是如何工作的?
Protobuf 使用二進制數據格式,與基于文本的格式相比,它更緊湊且讀寫速度更快。它還提供了接口定義語言(IDL),可以輕松定義要序列化的數據的結構。
Protobuf 文件使用文件擴展名保存.proto。該.proto文件以 Protobuf 的 IDL 格式編寫,包含有關數據結構的所有信息。數據被建模為“消息”,即名稱/值對組。以下是文件中簡單 Protobuf 消息的示例.proto:
// 指定 Protobuf 版本為版本 3(最新版本)
syntax = "proto3";// 指定protobuf包名,防止類名重復
package com.shamee.protobuf;// 生成的文件存放在哪個包下
option java_package = "com.shamee.protos";// 生成的類名,如果沒有指定,會根據文件名自動轉駝峰來命名
option java_outer_classname = "PersonProtos";// 定義了一個Person類
message Person {// 后面的值(=1 =2)作為序列化后的二進制編碼中的字段的唯一標簽// 因此 1-15比 16 會少一個字節,所以盡量使用 1-15 來指定常用字段。int32 id = 1;string name = 2;string email = 3;string address = 4;
}
示例中,客戶消息包含四個字段:id、name、email和address。每個字段都有其類型指示,以及指示其是否為required、optional或 的標簽repeated。
該.proto文件可以使用 Protoc(即 Protobuf 編譯器)編譯成多種編程語言。該編譯器以開發人員指定的編程語言生成源代碼。該源代碼包括用于寫入、讀取和操作.proto文件中定義的消息類型的類和方法。
當有數據要存儲或傳輸時,可以創建生成的類的實例并用您的數據填充它們。然后將這些實例序列化為二進制格式。讀取數據時,二進制格式將反序列化回從.proto文件生成的類的實例。這使您可以輕松訪問結構化數據。
Protobuf 生成的二進制數據格式是平臺無關的,可用于在不同系統、應用程序或服務之間交換數據,即使它們是用不同的編程語言實現或在不同的平臺上運行的。
2.3、如何使用 Protoc 生成代碼?
上面定義好的.proto,可以使用Protobbuf編譯器(Protoc)將文件編譯成不同語言。
下載編譯器:Release Protocol Buffers v25.3 · protocolbuffers/protobuf · GitHub
編譯命令如下面的代碼將.proto文件編譯成 JavaScript:
protoc --js_out=import_style=commonjs,binary: .customers.proto
編譯成java語言:
protoc --java_out=./my_dist .customers.proto
3、Springboot集成
上面介紹了protobuf的基本內容,以及簡單的語法編寫和編譯。接下來我們來使用他,并集成到我們的springboot中。
3.1、引入依賴
<dependency><groupId>com.google.protobuf</groupId><artifactId>protobuf-java</artifactId><version>3.6.1</version>
</dependency>
<!-- 同時添加maven插件,用于編譯protobuf生成java文件 -->
<build><extensions><extension><groupId>kr.motd.maven</groupId><artifactId>os-maven-plugin</artifactId><version>1.5.0.Final</version></extension></extensions><plugins><plugin><groupId>org.xolstice.maven.plugins</groupId><artifactId>protobuf-maven-plugin</artifactId><version>0.5.0</version><configuration><protocArtifact>com.google.protobuf:protoc:3.1.0:exe:${os.detected.classifier}</protocArtifact><!--默認值,proto源文件路徑--><protoSourceRoot>${project.basedir}/src/main/resources/proto</protoSourceRoot><pluginId>grpc-java</pluginId><!--是否清空上面配置目錄outputDirectory--><clearOutputDirectory>false</clearOutputDirectory></configuration><executions><execution><goals><goal>compile</goal></goals></execution></executions></plugin><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-jar-plugin</artifactId><version>3.3.0</version><configuration><excludes><exclude>**/*.proto</exclude></excludes></configuration></plugin></plugins>
</build>
3.2、定義Proto文件
定義兩個proto文件,一個用于接收接口請求數據Person.proto,一個用于響應Response.proto。
Person.proto:
syntax = "proto3";
package proto.shamee;// 生成的文件存放在哪個包下
option java_package = "proto.shamee";// 生成的類名,如果沒有指定,會根據文件名自動轉駝峰來命名
option java_outer_classname = "PersonProto";// 定義了一個Person類
message Person {// 后面的值(=1 =2)作為序列化后的二進制編碼中的字段的唯一標簽// 因此 1-15比 16 會少一個字節,所以盡量使用 1-15 來指定常用字段。int32 id = 1;string name = 2;string email = 3;string address = 4;
}
Response.proto:
syntax = "proto3";
package proto.shamee;
option java_package = "proto.shamee";
option java_outer_classname = "ResponseProto";message Response {int32 code = 1;string message = 2;string data = 3;
}
3.3、Protobuf生成Java代碼
定義完后,可以直接mvn install,可以生成響應的proto的java代碼。
3.4、配置Protobuf的序列化和反序列化
@Configuration
public class ProtobufConfig {/*** protobuf 序列化*/@BeanProtobufHttpMessageConverter protobufHttpMessageConverter() {return new ProtobufHttpMessageConverter();}/*** protobuf 反序列化*/@BeanRestTemplate restTemplate(ProtobufHttpMessageConverter protobufHttpMessageConverter) {return new RestTemplate(Collections.singletonList(protobufHttpMessageConverter));}}
3.5、定義controller接口
由于protobuf是基于二進制流傳輸數據,因此這里需要指定一下x-protobuf協議。
@RestController
@RequestMapping("/test")
public class TestController {@PostMapping(value = "/index", produces = "application/x-protobuf")public ResponseProto.Response index(@RequestBody PersonProto.Person person){return ResponseProto.Response.newBuilder().setCode(200).setMessage("OK").setData("hello:" + person.getName()).build();}}
接著就可以啟動springboot項目啦。
3.6、訪問
這里訪問的時候,需要定義header的content-type,同時參數以二進制數據進行傳輸訪問。我們的請求數據:
訪問頭配置:
返回:
到此我們就簡單的學會了protobuf了,又可以安心的去吃夜宵了。
4、小結
protobuf在整個集成中還是有一些問題,如ptotoc的版本號如果相差太多就會編譯不通過。當然protobuf也存在一些不足之處:
- 功能簡單:Protobuf 功能簡單,無法用來表示復雜的概念。例如,它無法表示 XML 中的DTD 或 XSD 等復雜結構。
- 通用性較差:Protobuf 是 Google 內部使用的工具,通用性較差。XML 和 JSON 已成為多種行業標準的編寫工具,而 Protobuf 在通用性上還差很多。
- 自解釋性差:Protobuf 以二進制形式存儲數據,不便于閱讀和編輯。XML 具有自解釋性,可以直接用文本編輯器打開和編輯。
Protobuf 是一種優秀的序列化格式,但并非完美無缺。在選擇序列化格式時,需要根據實際需求進行綜合考慮。如果需要一種高效、緊湊、可擴展的序列化格式,Protobuf 是一個不錯的選擇。但如果需要表示復雜的概念、通用性或自解釋性,則需要考慮其他序列化格式。