Spring Boot集成protobuf快速入门Demo
1.什么是protobuf?
Protobuf(Protocol Buffers)是由 Google 开发的一种轻量级、高效的数据交换格式,它被用于结构化数据的序列化、反序列化和传输。相比于 XML 和 JSON 等文本格式,Protobuf 具有更小的数据体积、更快的解析速度和更强的可扩展性。 Protobuf 的核心思想是使用协议(Protocol)来定义数据的结构和编码方式。使用 Protobuf,可以先定义数据的结构和各字段的类型、字段等信息,然后使用 Protobuf 提供的编译器生成对应的代码,用于序列化和反序列化数据。由于 Protobuf 是基于二进制编码的,因此可以在数据传输和存储中实现更高效的数据交换,同时也可以跨语言使用。
Protobuf 有以下几个优势:
- 更小的数据量:Protobuf 的二进制编码通常只有 XML 和 JSON 的 1/3 到 1/10 左右,因此在网络传输和存储数据时可以节省带宽和存储空间。
- 更快的序列化和反序列化速度:由于 Protobuf 使用二进制格式,所以序列化和反序列化速度比 XML 和 JSON 快得多。
- 跨语言:Protobuf 支持多种编程语言,可以使用不同的编程语言来编写客户端和服务端。这种跨语言的特性使得 Protobuf 受到很多开发者的欢迎(JSON 也是如此)。
- 易于维护可扩展:Protobuf 使用 .proto 文件定义数据模型和数据格式,这种文件比 XML 和 JSON 更容易阅读和维护,且可以在不破坏原有协议的基础上,轻松添加或删除字段,实现版本升级和兼容性。
2.代码工程
实验目标
rest api实现基于Protobuf 协议通信
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>3.2.1</version></parent><modelVersion>4.0.0</modelVersion><artifactId>protobuf</artifactId><properties><maven.compiler.source>17</maven.compiler.source><maven.compiler.target>17</maven.compiler.target></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-autoconfigure</artifactId></dependency><dependency><groupId>com.google.protobuf</groupId><artifactId>protobuf-java</artifactId><version>3.19.2</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-test</artifactId><scope>test</scope></dependency></dependencies>
<build><extensions><extension><groupId>kr.motd.maven</groupId><artifactId>os-maven-plugin</artifactId><version>1.6.1</version></extension></extensions><plugins><plugin><groupId>org.xolstice.maven.plugins</groupId><artifactId>protobuf-maven-plugin</artifactId><version>0.6.1</version><configuration><protoSourceRoot>${basedir}/src/main/resources</protoSourceRoot><protocArtifact>com.google.protobuf:protoc:3.19.1:exe:${os.detected.classifier}</protocArtifact><pluginArtifact>io.grpc:protoc-gen-grpc-java:1.43.1:exe:${os.detected.classifier}</pluginArtifact><outputDirectory>src/main/java</outputDirectory><clearOutputDirectory>false</clearOutputDirectory><pluginId>grpc-java</pluginId></configuration><executions><execution><goals><goal>compile</goal><goal>compile-custom</goal></goals></execution></executions></plugin><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins>
</build></project>
controller
package com.et.protobuf.controller;import com.et.protobuf.PhoneNumJson;
import com.et.protobuf.ProtobufMessage;
import com.et.protobuf.StudentJson;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;@RestController
public class HelloWorldController {@RequestMapping("/json/{id}")public StudentJson showHelloWorld(@PathVariable Integer id){StudentJson studentJson = new StudentJson();studentJson.setId(id);studentJson.setFirstName("maxsm");studentJson.setLastName("sdfsdfsdfsdfsdfsdsdfsdfsdfsdfsdfsdfsdfsdf");studentJson.setEmail("1224sdfsfsdf344552@163.com");PhoneNumJson phoneNumJson = new PhoneNumJson();phoneNumJson.setNumber("12345sdfsdfsd6566666");phoneNumJson.setType(1);List<PhoneNumJson> list = new ArrayList<>();list.add(phoneNumJson);studentJson.setPhoneNumList(list);return studentJson;}@RequestMapping("/protobuf/{id}")ProtobufMessage.Student protobuf(@PathVariable Integer id) {return ProtobufMessage.Student.newBuilder().setId(id).setFirstName("maxsm").setLastName("sdfsdfsdfsdfsdfsdsdfsdfsdfsdfsdfsdfsdfsdf").setEmail("1224sdfsfsdf344552@163.com").addPhone(ProtobufMessage.Student.PhoneNumber.newBuilder().setNumber("12345sdfsdfsd6566666").setType(ProtobufMessage.Student.PhoneType.MOBILE).build()).build();}}
entity
package com.et.protobuf;import java.util.List;/*** @author liuhaihua* @version 1.0* @ClassName StudentJson* @Description todo* @date 2024/08/05/ 16:32*/
public class StudentJson {private int id;private String firstName;private String lastName;private String email;private List<PhoneNumJson> phoneNumList;public int getId() {return id;}public void setId(int id) {this.id = id;}public String getFirstName() {return firstName;}public void setFirstName(String firstName) {this.firstName = firstName;}public String getLastName() {return lastName;}public void setLastName(String lastName) {this.lastName = lastName;}public String getEmail() {return email;}public void setEmail(String email) {this.email = email;}public List<PhoneNumJson> getPhoneNumList() {return phoneNumList;}public void setPhoneNumList(List<PhoneNumJson> phoneNumList) {this.phoneNumList = phoneNumList;}
}
package com.et.protobuf;/*** @author liuhaihua* @version 1.0* @ClassName PhoneNum* @Description todo* @date 2024/08/05/ 16:35*/public class PhoneNumJson {private int type;private String number;public int getType() {return type;}public void setType(int type) {this.type = type;}public String getNumber() {return number;}public void setNumber(String number) {this.number = number;}
}
mxsm.proto
使用 Protobuf 的语言定义文件(.proto)可以定义要传输的信息的数据结构,可以包括各个字段的名称、类型等信息。同时也可以相互嵌套组合,构造出更加复杂的消息结构。
syntax = "proto3";
package mxsm;
option java_package = "com.et.protobuf";
option java_outer_classname = "ProtobufMessage";message Course {int32 id = 1;string course_name = 2;repeated Student student = 3;
}
message Student {int32 id = 1;string first_name = 2;string last_name = 3;string email = 4;repeated PhoneNumber phone = 5;message PhoneNumber {string number = 1;PhoneType type = 2;}enum PhoneType {MOBILE = 0;LANDLINE = 1;}
}
头部全局定义
syntax = "proto3";
指定 Protobuf 版本为版本 3(最新版本)package com.wdbyte.protobuf;
指定 Protobuf 包名,防止有相同类名的message
定义,这个包名是生成的类中所用到的一些信息的前缀,并非类所在包。option java_multiple_files = true;
是否生成多个文件。若false
,则只会生成一个类,其他类以内部类形式提供。option java_package =
生成的类所在包。option java_outer_classname
生成的类名,若无,自动使用文件名进行驼峰转换来为类命名。
消息结构具体定义
message Person
定一个了一个 Person 类。 Person 类中的字段被 optional
修饰,被 optional
修饰说明字段可以不赋值。
- 修饰符
optional
表示可选字段,可以不赋值。 - 修饰符
repeated
表示数据重复多个,如数组,如 List。 - 修饰符
required
表示必要字段,必须给值,否则会报错RuntimeException
,但是在 Protobuf 版本 3 中被移除。即使在版本 2 中也应该慎用,因为一旦定义,很难更改。
字段类型定义
修饰符后面紧跟的是字段类型,如 int32
、string
。常用的类型如下:
int32、int64、uint32、uint64
:整数类型,包括有符号和无符号类型。float、double
:浮点数类型。bool
:布尔类型,只有两个值,true 和 false。string
:字符串类型。bytes
:二进制数据类型。enum
:枚举类型,枚举值可以是整数或字符串。message
:消息类型,可以嵌套其他消息类型,类似于结构体。
字段后面的 =1,=2
是作为序列化后的二进制编码中的字段的对应标签,因为 Protobuf 消息在序列化后是不包含字段信息的,只有对应的字段序号,所以节省了空间。也因此,1-15 比 16 会少一个字节,所以尽量使用 1-15 来指定常用字段。且一旦定义,不要随意更改,否则可能会对不上序列化信息。
config
package com.et.protobuf.config;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.protobuf.ProtobufHttpMessageConverter;
import org.springframework.web.client.RestTemplate;import java.util.Arrays;@Configuration
public class Config {@BeanRestTemplate restTemplate(ProtobufHttpMessageConverter hmc) {return new RestTemplate(Arrays.asList(hmc));}@BeanProtobufHttpMessageConverter protobufHttpMessageConverter() {return new ProtobufHttpMessageConverter();}
}
以上只是一些关键代码,所有代码请参见下面代码仓库
代码仓库
- GitHub - Harries/springboot-demo: a simple springboot demo with some components for example: redis,solr,rockmq and so on.(Protobuf)
3.测试
启动Spring Boot应用
编写测试类
package com.et.protobuf;import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.protobuf.ProtobufHttpMessageConverter;
import org.springframework.web.client.RestTemplate;import java.util.ArrayList;
import java.util.List;@SpringBootTest(classes = DemoApplication.class)
public class ApplicationTest {// Other declarationsprivate static final String COURSE1_URL = "http://localhost:8088/protobuf/1";@Autowiredprivate RestTemplate restTemplate ;@Testpublic void whenUsingRestTemplate_thenSucceed() {ResponseEntity<ProtobufMessage.Student> student = restTemplate.getForEntity(COURSE1_URL, ProtobufMessage.Student.class);System.out.println(student.toString());}
}
结果如下
<200 OK OK,id: 1
first_name: "maxsm"
last_name: "sdfsdfsdfsdfsdfsdsdfsdfsdfsdfsdfsdfsdfsdf"
email: "1224sdfsfsdf344552@163.com"
phone {number: "12345sdfsdfsd6566666"
}
,[X-Protobuf-Schema:"mxsm.proto", X-Protobuf-Message:"mxsm.Student", Content-Type:"application/x-protobuf;charset=UTF-8", Transfer-Encoding:"chunked", Date:"Mon, 05 Aug 2024 09:10:55 GMT", Keep-Alive:"timeout=60", Connection:"keep-alive"]>
Json和protobuf性能比较
单个线程,循环1分钟
测试结果发现json性能甚至优于protobuf,并不符合预期结果!是我哪一步整错了吗?有大神知道怎么回事吗?
4.引用
- Overview | Protocol Buffers Documentation
相关文章:

Spring Boot集成protobuf快速入门Demo
1.什么是protobuf? Protobuf(Protocol Buffers)是由 Google 开发的一种轻量级、高效的数据交换格式,它被用于结构化数据的序列化、反序列化和传输。相比于 XML 和 JSON 等文本格式,Protobuf 具有更小的数据体积、更快…...

SpringBoot+Vue 简单小文章项目开发全过程
文章目录 一、项目介绍二、需求设计三、数据库设计四、项目构建项目技术选型:构建项目说明:项目架构mavenMySQLRedis 五、项目开发:项目开发思路:项目开发过程:1. 导入文件包/新建项目2. 新建子模块:common模块pojo模块server模块…...

如何将发明原理应用于产品设计的概念阶段?
众所周知,产品设计的概念阶段是创意孵化的关键时期,它决定了产品的方向、定位及核心卖点。在这一阶段,将发明原理融入其中,能够极大地拓宽思维边界,激发前所未有的设计灵感。具体步骤如深圳天行健企业管理咨询公司下文…...

【wsl】wsl + vscode 中使用 typora 打开 markdown 文件
vscode 连接好wsl 使用Open in External App 一个五星好评的插件Open in External App则可以在vscode中用typora打开md文件,不仅如此,还有设定其他应用打开相应的文件,比如chrome打开html。插件食用方法也比较简单,安装后&#…...
AutoDL下huggingface下载模型位置问题
AutoDL系统盘只有30G,数据盘有50G且可扩容,模型及数据集空间通常较大,为节省系统盘空间,我们将文件都存储于数据盘,在运行的代码最前端(一定要在最前面)添加 import os os.environ[HF_HOME] /…...

SpringBoot基础(一):快速入门
SpringBoot基础系列文章 SpringBoot基础(一):快速入门 目录 一、SpringBoot简介二、快速入门三、SpringBoot核心组件1、parent1.1、spring-boot-starter-parent1.2、spring-boot-dependencies 2、starter2.1、spring-boot-starter-web2.2、spring-boot-starter2.3、…...
使用Weka进行数据挖掘与机器学习
在当前大数据时代,数据挖掘与机器学习已经成为了不可或缺的技术。而Weka是一个非常流行的机器学习软件,它提供了一整套的机器学习算法和数据处理工具。Weka不仅支持命令行操作和GUI,还提供了Java API,非常适合Java开发者进行数据挖…...
定时器知识点
#视频教程: 11.TIM定时中断 CSDN教程 知识点: 1.时钟源选择图 ![[Pasted Image 20240802103525_114.png]] 基本定时器 2个功能 :只能定时中断和主模式触发DAC的功能 知识点 1.时基单元:预分配器(PSC)、…...

桌面日历还能这样玩?这个日历太酷了吧!秒变桌面记事本!
大家应该有经常看日历的习惯,每个人都有不同的日历需求。特别是一些节假日,重要节日时候,大家看日历的频次就比较高了,如何选一款好用的日历?我们给大家展示一款非常不错的桌面日历,看下你喜不喜欢…...
基于深度学习的太阳暗条检测(2020年以来)
A universal method for solar filament detection from Hα observations using semi-supervised deep learning A&A, 686, A213 (2024) A universal method for solar filament detection from Hα observations using semi-supervised deep learning (aanda.org) ABS…...

【吊打面试官系列-Elasticsearch面试题】Elasticsearch 在部署时,对 Linux 的设置有哪些优化方法?
大家好,我是锋哥。今天分享关于 【Elasticsearch 在部署时,对 Linux 的设置有哪些优化方法?】面试题,希望对大家有帮助; Elasticsearch 在部署时,对 Linux 的设置有哪些优化方法? 面试官 :想了解对 ES 集…...

MySQL·C/C++访问数据库
目录 准备工作 测试是否安装成功 C/C语言访问 官方文档 接口介绍使用 mysql_init() mysql_close() 补充1:makefile编写 mysql_real_connect() 测试1:编译链接 mysql_query() 测试2:SQL语句测试 改 增 删 查 错误1&#x…...

python.tkinter设计标记语言(渲染2-渲染器)
TOC 前言 本文仅作为笔记记录。 在前文中,我们通过标记意义解释生成了带有明确渲染要求的参数组,以<title>为例,我们获取了title, level两个明确的渲染标记,这一部分由Tin标记解释器完成,不需要编写者花费过多…...

Cadence学习笔记 Day0 Cadence17.4环境安装
当然是选择“吴法安装” 直接跟着吴川斌博客的方法来就可以了,这里大致记录一下我的安装步骤: 安装许可证管理器破解许可证管理器安装软件以及补丁破解软件 获取 直接放出链接:吴川斌的博客 下载得到: 一、安装许可证管理器&am…...

k8s创建secret并在container中获取secret
k8s创建secret并在container中获取secret 本文使用的deployment和service与我的上一篇文章一样。link也放在下面了,如果不懂什么事deployment和service,可以先看我的上一篇文章。 k8s使用kustomize来部署应用 下面我们将通过创建secret开始。secret是我…...

Leetcode每日一题之仅仅反转字母(C++)
在学习之余对于知识的巩固也尤为重要,不论难度高低,都会对代码的理解有所加深,下面我们开始练习 思路解析 关于本题的核心思路就是如何判断字符串中元素是否为字母以及如何遍历字符串以达到仅反转的目的,这里用到的知识就是关于 s…...

PDF预览:利用vue3-pdf-app实现前端PDF在线展示
目录 PDF预览:利用vue3-pdf-app实现前端PDF在线展示 一、vue3-pdf-app组件介绍及其优点 1、vue3-pdf-app是什么 2、作用与场景 3、类似的插件 二、项目初始化与依赖安装 1、初始化Vue3项目 2、安装依赖 三、集成vue3-pdf-app插件 1、引入插件 2、配置组件…...

【OpenCV C++20 学习笔记】拉普拉斯(Laplace)二阶求导-边缘检测
拉普拉斯二阶求导 原理拉普拉斯算子(Laplacian Operator) API实例 原理 在OpenCV中,Sobel算法可以对图片中的值求一阶导数,从而计算出图片中的边缘线。其原理如下面的示意图: 那么,如果再求一次导数的,即求二阶导数&…...

MySQL的下载和安装步骤
一、数据库概述 我们先来了解三个概念:数据库、数据库管理系统、SQL。 名称全称简称数据库存储数据的仓库,数据是有组织的进行存储DataBase(DB)数据库管理系统操纵和管理数据库的大型软件DataBase Management System (DBMS)SQL操…...

Java国际版同城服务美容美发到店服务上门服务系统
🌍全球美妆新风尚!国际版同城服务,美容美发一键享 🏙️【国际视野,同城便捷】🏙️ 在这个全球化的时代,美丽不再受地域限制!国际版同城服务系统,将全球顶尖的美容美发资…...

Chapter03-Authentication vulnerabilities
文章目录 1. 身份验证简介1.1 What is authentication1.2 difference between authentication and authorization1.3 身份验证机制失效的原因1.4 身份验证机制失效的影响 2. 基于登录功能的漏洞2.1 密码爆破2.2 用户名枚举2.3 有缺陷的暴力破解防护2.3.1 如果用户登录尝试失败次…...

XCTF-web-easyupload
试了试php,php7,pht,phtml等,都没有用 尝试.user.ini 抓包修改将.user.ini修改为jpg图片 在上传一个123.jpg 用蚁剑连接,得到flag...
蓝桥杯 2024 15届国赛 A组 儿童节快乐
P10576 [蓝桥杯 2024 国 A] 儿童节快乐 题目描述 五彩斑斓的气球在蓝天下悠然飘荡,轻快的音乐在耳边持续回荡,小朋友们手牵着手一同畅快欢笑。在这样一片安乐祥和的氛围下,六一来了。 今天是六一儿童节,小蓝老师为了让大家在节…...
服务器硬防的应用场景都有哪些?
服务器硬防是指一种通过硬件设备层面的安全措施来防御服务器系统受到网络攻击的方式,避免服务器受到各种恶意攻击和网络威胁,那么,服务器硬防通常都会应用在哪些场景当中呢? 硬防服务器中一般会配备入侵检测系统和预防系统&#x…...

【快手拥抱开源】通过快手团队开源的 KwaiCoder-AutoThink-preview 解锁大语言模型的潜力
引言: 在人工智能快速发展的浪潮中,快手Kwaipilot团队推出的 KwaiCoder-AutoThink-preview 具有里程碑意义——这是首个公开的AutoThink大语言模型(LLM)。该模型代表着该领域的重大突破,通过独特方式融合思考与非思考…...
WEB3全栈开发——面试专业技能点P2智能合约开发(Solidity)
一、Solidity合约开发 下面是 Solidity 合约开发 的概念、代码示例及讲解,适合用作学习或写简历项目背景说明。 🧠 一、概念简介:Solidity 合约开发 Solidity 是一种专门为 以太坊(Ethereum)平台编写智能合约的高级编…...

GitFlow 工作模式(详解)
今天再学项目的过程中遇到使用gitflow模式管理代码,因此进行学习并且发布关于gitflow的一些思考 Git与GitFlow模式 我们在写代码的时候通常会进行网上保存,无论是github还是gittee,都是一种基于git去保存代码的形式,这样保存代码…...

基于IDIG-GAN的小样本电机轴承故障诊断
目录 🔍 核心问题 一、IDIG-GAN模型原理 1. 整体架构 2. 核心创新点 (1) 梯度归一化(Gradient Normalization) (2) 判别器梯度间隙正则化(Discriminator Gradient Gap Regularization) (3) 自注意力机制(Self-Attention) 3. 完整损失函数 二…...

【网络安全】开源系统getshell漏洞挖掘
审计过程: 在入口文件admin/index.php中: 用户可以通过m,c,a等参数控制加载的文件和方法,在app/system/entrance.php中存在重点代码: 当M_TYPE system并且M_MODULE include时,会设置常量PATH_OWN_FILE为PATH_APP.M_T…...

论文阅读:LLM4Drive: A Survey of Large Language Models for Autonomous Driving
地址:LLM4Drive: A Survey of Large Language Models for Autonomous Driving 摘要翻译 自动驾驶技术作为推动交通和城市出行变革的催化剂,正从基于规则的系统向数据驱动策略转变。传统的模块化系统受限于级联模块间的累积误差和缺乏灵活性的预设规则。…...