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.mzph.cn/news/769288.shtml

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

相关文章

【vscode打开多文件夹】

1)将文件夹添加到工作空间中 2)文件夹方式展开 3)最终效果 小技巧&#xff1a; 文件夹的位置不对的话&#xff0c;可以拖动进行调整。

Linux--动静态库的原理和使用详解

本文介绍了Linux系统中动态库与静态库的概念、原理以及使用方法。通过深入讲解动态库与静态库的区别和优劣势&#xff0c;帮助读者更好地理解并选择合适的库类型来进行软件开发。 动态库和静态库的概念 动态库&#xff08;Dynamic Link Library&#xff0c;简称DLL&#xff09…

优化金融展厅设计,细节提升客户体验与实用效能

“很赚钱”大部分公众对金融行业的第一印象&#xff0c;这足以见得金融行业在社会经济发展中的重要性&#xff0c;而为了更好的宣传和科普金融相关信息&#xff0c;金融展厅的设计和建设成为了重要措施&#xff0c;它能够充分展示金融机构的实力、品牌形象和服务优势&#xff0…

Jmeter使用BeanShell保存数据到文件

1、目的 在使用jmeter压测时&#xff0c;业务上下连贯&#xff0c;需要对一些编号进行关联操作。这里使用‘JSON提取器’将值提取出来&#xff0c;后面请求可以直接使用。其它业务想要使用就只能把值保存到文件&#xff0c;再使用文件做参数化了。 2、JSON提取器 提取请求值 提…

网站监控工具必要的功能

什么是网站监控 网站监控是持续跟踪网站在互联网上的性能和可用性&#xff0c;以确保其正常运行并提供良好的用户体验的过程&#xff0c;在当今的数字时代&#xff0c;一个表现良好的网站对公司的声誉至关重要&#xff0c;打开速度慢的网站会对用户体验产生负面影响&#xff0…

leetcode 347.前K个高频元素

题目 思路 1.统计每个数出现的次数&#xff1a;可以用HashMap。key为num,value为这个数出现的次数。 2.怎样返回HashMap中value最大的前k个key呢&#xff1f; 这里用优先队列的方法&#xff08;本质是堆&#xff09; 我们要维护一个小根堆。我们在堆中存储&#xff08;key,…

APP信息收集思路总结(反代理,反虚拟机,反证书校验思路整理)

前言 本文是我在学习过程中的总结&#xff0c;希望可以被指导提议指正。 APP概况 app跟一个网站很像。 网站分为前端后端。 app就好像网站的前端一样&#xff0c;app不需要浏览器&#xff0c;而前端需要浏览器。 他们都需要服务器&#xff0c;也就是说&#xff0c;进行we…

实现登录拦截功能

1.4、实现登录拦截功能 温馨小贴士&#xff1a;tomcat的运行原理 当用户发起请求时&#xff0c;会访问我们像tomcat注册的端口&#xff0c;任何程序想要运行&#xff0c;都需要有一个线程对当前端口号进行监听&#xff0c;tomcat也不例外&#xff0c;当监听线程知道用户想要和…

#Linux(make工具和makefile文件以及makefile语法)

&#xff08;一&#xff09;发行版&#xff1a;Ubuntu16.04.7 &#xff08;二&#xff09;记录&#xff1a; &#xff08;1&#xff09;make为编译辅助工具&#xff0c;解决用命令编译工程非常繁琐的问题 &#xff08;2&#xff09;在终端键入make即可调用make工具&#xff0…

huawei 华为 交换机 配置 LACP 模式的链路聚合示例 (交换机之间直连)

组网需求 如 图 3-22 所示&#xff0c; SwitchA 和 SwitchB 通过以太链路分别都连接 VLAN10 和 VLAN20 的网络&#xff0c;且SwitchA 和 SwitchB 之间有较大的数据流量。用户希望 SwitchA 和 SwitchB 之间能够提供较大的链路带宽来使相同VLAN 间互相通信。在两台 Switch 设备上…

攻防演练利器:六款蓝队开源防御工具特点剖析

实战化的攻防演习活动一般具有时间短、任务急等特点&#xff0c;作为防守方&#xff0c;蓝队需要在日常安全运维工作的基础上&#xff0c;从攻击者角度出发&#xff0c;了解攻击者的思路与打法&#xff0c;并结合本单位实际网络环境、运营管理情况&#xff0c;制定相应的技术防…

性能测试丨GreatSQL TPC-H 性能测试报告正式发布!

1、测试背景概述 本次测试针对GreatSQL开源数据库基于标准 TPC-H 场景的测试。 TPC-H&#xff08;商业智能计算测试&#xff09;是美国交易处理效能委员会&#xff08;TPC&#xff0c;TransactionProcessing Performance Council&#xff09;组织制定的用来模拟决策支持类应用…

抽取CLOB字段中XML的特定元素的VALUE值

在ORACLE数据库中&#xff0c;有时XML文件会被保存在CLOB字段中。 这时候&#xff0c;若是我们要获取此字段XML中特定元素的VALUE值&#xff0c;就需要用到xmltype 这个函数。 如下面的 XML文件&#xff0c;保存在 TABLE_A 的CLOB_K 字段&#xff0c;若是我们要获取其中的 Y…

C语言从入门到精通(第5版)-----读书笔记

第一章 C语言概述 1.1 C语言的发展史 1.1.1程序语言简述 1、机器语言 低级语言&#xff0c;又称二进制代码语言。一种使用0、1表示的二进制代码编写指令以执行计算机操作的语言。 特点&#xff1a;计算机可以直接识别&#xff0c;不需要进行任何翻译。 2、汇编语言 为了减…

RDMA内核态通信测试krping学习

krping模块是一个内核可加载模块&#xff0c;它实现了客户机/服务器ping/pong程序&#xff0c;这个模块仅仅为了测试内核rdma的API&#xff08;单边的READ和Write&#xff1b;双边的SEND和RECEIVE&#xff09;。该模块允许通过一个名为/proc/krping的/proc条目建立连接并运行pi…

ElasticSearch8 - 基本操作

前言 本文记录 ES 的一些基本操作&#xff0c;就是对官方文档的一些整理&#xff0c;按自己的习惯重新排版&#xff0c;凑合着看。官方的更详细&#xff0c;建议看官方的。 下文以 books 为索引名举例。 新增 添加单个文档 (没有索引会自动创建) POST books/_doc {"n…

服务器总是宕机问题记录

博主介绍&#xff1a; 22届计科专业毕业&#xff0c;来自湖南&#xff0c;主要是在CSDN记录一些自己在Java开发过程中遇到的一些问题&#xff0c;欢迎大家一起讨论学习&#xff0c;也欢迎大家的批评指正。 文章目录 背景调整总结 背景 2核2G的服务器&#xff0c;服务器安装了t…

计算机网络:物理层中的数字传输系统全景概览解析

✨✨ 欢迎大家来访Srlua的博文&#xff08;づ&#xffe3;3&#xffe3;&#xff09;づ╭❤&#xff5e;✨✨ &#x1f31f;&#x1f31f; 欢迎各位亲爱的读者&#xff0c;感谢你们抽出宝贵的时间来阅读我的文章。 我是Srlua小谢&#xff0c;在这里我会分享我的知识和经验。&am…

Django之Celery篇(三)

一、任务交给Celery Django任务交给Celery的方法和普通使用Celery任务的调用基本无区别,只是将执行代码的放到到View视图中 而获取结果,往往并不能把结果和第1次请求一起响应,若想获取结果是通过第2次请求获取结果 代码如下: from django.http import HttpResponsefrom …

华为ensp中vrrp虚拟路由器冗余协议 原理及配置命令

CSDN 成就一亿技术人&#xff01; 作者主页&#xff1a;点击&#xff01; ENSP专栏&#xff1a;点击&#xff01; CSDN 成就一亿技术人&#xff01; ————前言————— VRRP&#xff08;Virtual Router Redundancy Protocol&#xff0c;虚拟路由器冗余协议&#xff0…