Protobuf基础使用

Protobuf是什么

在我们日常编写代码的过程中,经常会涉及到网络传输的部分。我们通常会在网络之间传递各种各样的请求,但是在我们日常架构之中,经常会涉及后端服务器之间的通信,通信过程中,可能传递的对象就是一个类。这种情况下我们该如何在网络通信中传递类和对象的内容呢。目前市面上的方法也有很多,比如Json序列化,XML进行类的传递。但是一旦涉及到音视频和图片的传递之后该怎么办呢。有一种办法是把图片,音视频进行序列化成二进制数据后进行一个传输。

下列类就是基于java标准库提供的ObjectOutputStream实现的一个简易实现对象序列化的代码

package com.czl.myRabbitMq.commom;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;import java.io.*;
//将一个对象进行序列化和反序列化 java中的对象都可以通过一下逻辑进行序列化 但前提是实现接口 Serializable
@Slf4j
public class BinaryTransformTool {/*** 这样写是设置版本号的意思* 就是比如我今天定义了一个Message对象 对其进行了序列化 并存入了文件中* 要是第二天有人对Message对象进行修改 然后我如果读取该序列化数据 很大概率* 是会报错的 为了防止上述情况发生 这里定义一个版本表示 表示如果我今天定义版本一* 然后将数据序列化写入文件的时候 这个1这个数据就被保存下来了 要是有人对Message对象* 进行了修改 就手动加一 这样反序列化的时候就能防止读取旧版本数据了** 这个属性一般加在进行序列化的对象中 而不是这里!!!!!!!!!!!!!!!!*/private static final long serialVersionUID = 1L;//将对象进行序列化操作@SneakyThrowspublic static byte[] getBinaryData(Object data){//因为我们不知道将对象转为二进制数据后 这个数据的长度是几个字节  所以我们使用//ByteArrayOutputStream 这个对象 这个对象本质是一个可变长的 字节数组try(ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream()) {//java标准库中提供了将对象序列化的类 就是 ObjectOutputStream 后面构造器中传入的参数就是//序列化时将数据写入的地方 这里传入的是byteArrayOutputStream 所以写入这个对象里面//要是传入的是文件 则写入文件里面try (ObjectOutputStream outputStream = new ObjectOutputStream(byteArrayOutputStream)) {outputStream.writeObject(data);}return byteArrayOutputStream.toByteArray();}}//将二进制数据转化为对象@SneakyThrowspublic static Object fromData(byte[] data){Object object;try (ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(data)){try(ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream)){object = objectInputStream.readObject();}return object;}}
}

但是上述代码是将一个对象和类进行序列化生成一个byte数组,有很多序列化的细节是没有实现的。特别是针对某一个类和对象的某个属性单独进行序列化。所以Protobuf是一个可以快速生成将对象序列化代码的一个组件。
以下是官方对Protobuf的说明以及翻译

Protocol Buffers 是 Google 的⼀种语⾔⽆关、平台⽆关、可扩展的序列化结构数据的⽅法,它可⽤
于(数据)通信协议、数据存储等。
Protocol Buffers 类⽐于 XML,是⼀种灵活,⾼效,⾃动化机制的结构数据序列化⽅法,但是⽐
XML 更⼩、更快、更为简单。
你可以定义数据的结构,然后使⽤特殊⽣成的源代码轻松的在各种数据流中使⽤各种语⾔进⾏编写和
读取结构数据。你甚⾄可以更新数据结构,⽽不破坏由旧数据结构编译的已部署程序。

Protobuf的基础使用

在maven项目中使用protobuf之前需要引入相关的依赖 下面的不是依赖是一个protobuf的插件用来快速对protobuf进行编译的。

<dependencies><dependency><groupId>com.google.protobuf</groupId><artifactId>protobuf-java</artifactId><version>4.26.0</version></dependency></dependencies><build><plugins><plugin><groupId>org.xolstice.maven.plugins</groupId><artifactId>protobuf-maven-plugin</artifactId><version>0.6.1</version><configuration><!-- 本地protoc.exe的目录--><protocExecutable>C:\protobuf\protobuf26.0\bin\protoc.exe</protocExecutable><!-- proto文件放置的位置--><protoSourceRoot>${project.basedir}/src/main/java/proto</protoSourceRoot><!-- 生成的java文件的目录--><outputDirectory>${project.basedir}/src/main/java</outputDirectory><!-- 在编译的时候是否删除目标目录下的文件 默认为true 最好为false 以免误删--><clearOutputDirectory>false</clearOutputDirectory></configuration></plugin></plugins></build>

首先我们先创建一个新的maven工程,然后在main/java目录下创建出一个proto目录用来存放我们的proto文件

 

此时我们可以进入proto文件中进行一个protobuf的代码编写了
在proto文件的首行中我们一般会指定当前proto文件使用的语法规则,(要是不指定的话默认使用的是proto2) proto3是最新版本的语法在proto2的基础上进行了优化,便于使用。

首行指定完语法之后,第二行一般会为当前proto文件指定一个名称空间(唯一) 用来标识当前文件和其他文件不冲突 

后面紧接着一般是选项 option后面带上一些参数

定义完之后就可以定义我们要生成的类的属性了,他就会自动帮我们生成当前类的序列化和反序列化方法。  在下面的代码中我们定义了一个学生类 其中带有2个属性 一个是name 一个是age,但是注意此时name后面跟的那个1不是name的值,而是字段的一个编号,且当前标号是不能重复的。

当前文件配置了三个选项,具体含义全在注释中

//首行proto 希望我们为当前文件指定一个版本
syntax = "proto3";
//表示当前proto文件的一个命名空间 避免定义的消息进行一个冲突
package start;
//是否可以将编译之后的Java代码分为多个文件进行存放 true 可以 false 不行
option java_multiple_files = true;//不配置这个只会生成一个文件
//想要生成的Java文件的package
option java_package = "com.ex.test1";
//编译完文件之后生成的类名
option java_outer_classname = "protoMy";//定义自定义的字段
//定义格式:
//定义类段 字段名  = 字段唯一编号; 字段编号一旦被使用就不要轻易改变了
//19000 - 19999 是源码的预留号 一般不设置这个区间的号码
//1到15之间的字段一般用来标记出现非常频繁的字段,为将来有可能添加的,频繁出现的字段预留一些出来
//因为在序列化的过程中,不仅仅要把值编译进去,还需要把对应的编号也编译进去,而1到15只需要一个字节即可编码了
//16-2047需要2个字节message MyTestStudent{string name = 1; //这个1不是字段的值 是字段的编号。 同时这个字段的编号不能重复int32 age = 2;
}

写完proto文件之后我们就可以开始编译了

protoc [--proto_path=IMPORT_PATH] --java_out=DST_DIR path/to/file.proto
在cmd中输入上述指令就可以编译了,但是这段指令的参数一大堆,是很麻烦的,这里就不得不提到开始引入依赖时,我们配置的快速编译插件了。

点击maven的图标 ,点击刷新找到出现的protobuf。就可以进行编译了 

可以看到在编译结束之后,出现了2个类和一个接口,其中咱们在proto文件中定义的MyTestStudent就自动生成出来了

我只写了2个参数生成代码都600行,所以这里我们不展示代码了 ,重点展示一下其中比较核心的内容。

 

可以看到这个类中,有一个内部类build

 

可以看到里面封装了关于我们描述属性的get和set方法,可以自己去瞅瞅太多了,这里不展示了

同时还有一个build方法可以把我们构造的属性构造成一个对象并返回

 

所以也就以为着我们需要使用builder对象来设置我们需要类的属性,并通过其中的build方法具体进行类的构造。

可以看到我们生成的类是继承了com.google.protobuf.GeneratedMessage这个对象

同时这个对象又继承了AbstractMessage这个对象

 

 AbstractMessage又继承了AbstractMessageLite这个对象,对象的序列化方法就在AbstractMessageLite中的

所以我们只需要调用我们生成类方法中的toByteArray就可以实现对象序列化了。

代码展示

下面是一段简单的使用代码 其中描述了我们对一个MyTestStudent对象进行序列化打印处序列化内容之后,在进行反序列化并打印出反序列化的结果。

import com.ex.test1.MyTestStudent;
import com.google.protobuf.InvalidProtocolBufferException;
public class Main {public static void main(String[] args) throws InvalidProtocolBufferException {MyTestStudent myTestStudent = MyTestStudent.newBuilder().setAge(18).setName("张三").build();byte[] by = myTestStudent.toByteArray();System.out.println(by.toString());MyTestStudent student = MyTestStudent.parseFrom(by);System.out.println(student.getName());}
}

下一篇写protobuf的语法和其他使用规则 

 

 

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/285556.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

大数据基础:Linux基础详解

课程介绍 本课程主要通过对linux基础课程的详细讲解&#xff0c;让大家熟练虚拟机的安装使用&#xff0c;Linux系统的安装配置&#xff0c;学习掌握linux系统常用命令的使用&#xff0c;常用的软件安装方法&#xff0c;制作快照&#xff0c;克隆&#xff0c;完成免密登录&…

springboot企业级抽奖项目业务三(活动模块)

梅开三度 开发流程 该业务基于rouyi生成好了mapper和service的代码&#xff0c;现在需要在controller层写接口 实际操作流程&#xff1a; 看接口文档一>controller里定义函数一>看给出的工具类一>补全controller里的函数一>运行测试 接口文档 在用户模块用户…

泰迪智能科技荣获山东省“技能兴鲁”职业技能大赛优秀组织奖

近日&#xff0c;泰迪智能科技荣获了山东省“技能兴鲁”职业技能大赛——第四届山东省“云数”技能竞赛“优秀组织单位”。 据悉&#xff0c;山东省“技能兴鲁”职业技能大赛——第四届山东省“云数”技能竞赛是由山东电子学会、山东省信息产业协会主办的&#xff0c;该竞赛是通…

32.HarmonyOS App(JAVA)鸿蒙系统app类自动生成GetSet方法

1.空白区域右键单击 2.选择Generate 3.选择getter,setter 4.选择列出的所有项 5.点击OK 6.成功生成。

说一说Java中的四种引用类型?

引言 在JDK1.2之前Java并没有提供软引用、弱引用和虚引用这些高级的引用类型。而是提供了一种基本的引用类型&#xff0c;称为Reference。并且当时Java中的对象只有两种状态&#xff1a;被引用和未被引用。当一个对象被引用时&#xff0c;它将一直存在于内存中&#xff0c;直到…

Spring Boot 实现定时任务动态管理

前言 本文主要介绍了SpringBoot架构下动态定时任务的使用&#xff0c;定时任务表达式配置在数据库中&#xff0c;通过反射执行到目标方法。 Quartz Quartz 是一个开源的作业调度框架,支持分布式定时任务&#xff0c;Quartz定时任务据我了解可分为Trigger&#xff08;触发器&…

毕业论文降重(gpt+完美降重指令),sci论文降重gpt指令——超级好用,重复率低于4%

1. 降重方法&#xff1a;gpt降重指令 2. gpt网站 https://yiyan.baidu.com/ https://chat.openai.com/ 3. 降重指令——非常好用&#xff01;&#xff01;sci论文&#xff0c;本硕大论文都可使用&#xff01; 请帮我把下面句子重新组织&#xff0c;通过调整句子逻辑&#xff0…

nvidia显卡如何安装cuda驱动

目录 查看显卡对应的cuda版本下载与你显卡匹配的CUDA Toolkit 查看显卡对应的cuda版本 按 微软 R 键&#xff0c;输入cmd 然后输入 nvidia-smi &#xff0c;回车显示下面信息&#xff1a; 看到 CUDA Version 为 12.2 下载与你显卡匹配的CUDA Toolkit 打开网页&#xff1a…

【项目管理——时间管理】【自用笔记】

1 项目时间管理&#xff08;进度管理&#xff09;概述 过程&#xff1a;&#xff08;2—6&#xff09;为规划过程组&#xff0c;7为监控过程组 题目定义&#xff1a;项目时间管理又称为进度管理&#xff0c;是指确保项目按时完成所需的过程。目标&#xff1a;时间管理的主要目标…

疲劳检测YOLOV8

疲劳检测YOLOV8&#xff0c;只需要OPENCV&#xff0c;采用YOLOV8训练得到PT模型&#xff0c;然后转换成ONNX&#xff0c;OPENCV调用&#xff0c;支持C/PYTHON/ANDROID开发疲劳检测YOLOV8

嵌入式开发--获取STM32产品系列的信息

嵌入式开发–获取STM32产品系列和容量信息 获取STM32产品系列 有时候我们需要知道当前MCU是STM32的哪一个系列&#xff0c;这当然可以从外部丝印看出来&#xff0c;但是运行在内部的软件如何知道呢&#xff1f; ST为我们提供了一个接口&#xff0c;F1和G4系列地址统一为&…

第十四届蓝桥杯省赛C++ A组所有题目以及题解(C++)【编程题均通过100%测试数据】

第一题《幸运数》【模拟】 【问题描述】 小蓝认为如果一个数含有偶数个数位&#xff0c;并且前面一半的数位之和等于后面一半的数位之和&#xff0c;则这个数是他的幸运数字。例如 2314是一个幸运数字,因为它有4个数位,并且2314。现在请你帮他计算从1至100000000之间共有多少…

李国武:如何评估一家精益制造咨询公司的实施能力?

在制造业转型升级的大背景下&#xff0c;精益制造已成为企业提升竞争力、实现可持续发展的关键。然而&#xff0c;面对市场上众多的精益制造咨询公司&#xff0c;如何评估其实施能力成为了众多企业的难题。本文将从多个方面为大家揭示评估精益制造咨询公司实施能力的方法&#…

Java实现JDBC编程

1 数据库编程的必备条件 编程语言&#xff0c;如Java&#xff0c;C、C、Python等 数据库&#xff0c;如Oracle&#xff0c;MySQL&#xff0c;SQL Server等 数据库驱动包&#xff1a;不同的数据库&#xff0c;对应不同的编程语言提供了不同的数据库驱动包&#xff0c;如&#x…

Linux-shell中变量的引用($变量名,${变量名})

1. 背景 最近写脚本时&#xff0c;发现有个变量在某个地方生效&#xff0c;某个地方又不生效&#xff0c;引用方式为 $变量名。 2. 方法 其实 shell 脚本中对变量的引用有两种方式&#xff1a; $变量名${变量名} 用下面的脚步&#xff0c;去测试效果&#xff1a; a100 b2…

前端Webpack5高级进阶课程

课程介绍 本套视频教程主要内容包含React/Vue最新版本脚手架分析、基于Webpack5编写自己的loader和plugin等&#xff0c;让你开发时选择更多样&#xff0c;最后&#xff0c;用不到一百行的代码实现Webpack打包。通过本套视频教程的学习&#xff0c;可以帮你彻底打通Webpack的任…

mineadmin前端安装启动

在上一篇文章中&#xff0c; 我们已经搭建好了后端环境并启动 mineadmin 快速安装部署&#xff08;docker环境&#xff09; 一、下载前端项目 1、在搭建后端时候&#xff0c;使用php bin/hyperf.php mine:install 的时候&#xff0c;有一个步骤是安装前端项目的。安装目录为&a…

简介:网络数据中心和数字孪生系统融合

前言 云服务器是在云中提供可扩展的计算服务&#xff0c;避免了使用传统服务器时需要预估资源用量及前期投入的情况。云服务器支持用户自定义一切资源&#xff1a;cpu、内存、硬盘、网络、安全等等&#xff0c;并可在访问量和负载等需求发生变化时轻松地调整它们。云服务器为业…

Visio导出高质量图片

直接导出图片比较糊&#xff0c; 在导出高质量图片&#xff0c;应该 直接保存&#xff0c;然后弹出此选项&#xff0c;进行如下设置 即可导出高质量图片

php 快速入门(一)

一、配置系统环境 1.1 安装软件 1、安装php的开发软件&#xff1a;phpstorm 在这个软件中写代码 2、安装php的运行软件&#xff1a;phpstduy 写好的php程序需要放到phpstduy中&#xff0c;用户才能访问和测试 安装过程注意事项&#xff1a;安装的路径中不能有空格和中文字符&…