13. Springboot集成Protobuf

目录

1、前言

2、Protobuf简介

2.1、核心思想

2.2、Protobuf是如何工作的?

[2.3、如何使用 Protoc 生成代码?](#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、引入依赖

XML 复制代码
<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:

XML 复制代码
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:

XML 复制代码
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的序列化和反序列化

java 复制代码
@Configuration
public class ProtobufConfig {

    /**
     * protobuf 序列化
     */
    @Bean
    ProtobufHttpMessageConverter protobufHttpMessageConverter() {
        return new ProtobufHttpMessageConverter();
    }

    /**
     * protobuf 反序列化
     */
    @Bean
    RestTemplate restTemplate(ProtobufHttpMessageConverter protobufHttpMessageConverter) {
        return new RestTemplate(Collections.singletonList(protobufHttpMessageConverter));
    }

}

3.5、定义controller接口

由于protobuf是基于二进制流传输数据,因此这里需要指定一下x-protobuf协议。

java 复制代码
@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 是一个不错的选择。但如果需要表示复杂的概念、通用性或自解释性,则需要考虑其他序列化格式。

相关推荐
小马爱打代码2 分钟前
SpringBoot原生实现分布式MapReduce计算
spring boot·分布式·mapreduce
数据最前线3 分钟前
Doris表设计与分区策略:让海量数据管理更高效
数据库
iuyou️5 分钟前
Spring Boot知识点详解
java·spring boot·后端
时光追逐者12 分钟前
MongoDB从入门到实战之MongoDB快速入门(附带学习路线图)
数据库·学习·mongodb
一弓虽17 分钟前
SpringBoot 学习
java·spring boot·后端·学习
姑苏洛言25 分钟前
扫码小程序实现仓库进销存管理中遇到的问题 setStorageSync 存储大小限制错误解决方案
前端·后端
头顶秃成一缕光35 分钟前
Redis的主从模式和哨兵模式
数据库·redis·缓存
AIGC大时代37 分钟前
高效使用DeepSeek对“情境+ 对象 +问题“型课题进行开题!
数据库·人工智能·算法·aigc·智能写作·deepseek
博睿谷IT99_38 分钟前
数据库证书可以选OCP认证吗?
数据库·oracle·开闭原则·ocp认证
光而不耀@lgy40 分钟前
C++初登门槛
linux·开发语言·网络·c++·后端