首页 > 编程语言 >ProtoBuf的介绍以及在Java中使用protobuf将对象进行序列化与反序列化

ProtoBuf的介绍以及在Java中使用protobuf将对象进行序列化与反序列化

时间:2023-03-23 11:02:45浏览次数:55  
标签:java protobuf proto DataInfo Student Java 序列化


场景

ProtoBuf简介

protocol buffers 是一种语言无关、平台无关、可扩展的序列化结构数据的方法,它可用于(数据)通信协议、数据存储等。

Protocol Buffers 是一种灵活,高效,自动化机制的结构数据序列化方法-可类比 XML,但是比 XML 更小(3 ~ 10倍)、更快(20 ~ 100倍)、更为简单。

你可以定义数据的结构,然后使用特殊生成的源代码轻松的在各种数据流中使用各种语言进行编写和读取结构数据。你甚至可以更新数据结构,而不破坏由旧数据结构编译的已部署程序。

ProtocolBuffer拥有多项比XML更高级的串行化结构数据的特性,ProtocolBuffer:

·        更简单

·        小3-10倍

·        快20-100倍

·        更少的歧义

·        可以方便的生成数据存取类

怎样使用ProtoBuf

定义proto描述文件

首先需要在一个 .proto 文件中定义你需要做串行化的数据结构信息。每个ProtocolBuffer信息是一小段逻辑记录,包含一系列的键值对。这里有个非常简单的 .proto 文件定义了个人信息:

message Person {
    required string name=1;
    required int32 id=2;
    optional string email=3;

    enum PhoneType {
        MOBILE=0;
        HOME=1;
        WORK=2;
    }

    message PhoneNumber {
        required string number=1;
        optional PhoneType type=2 [default=HOME];
    }

    repeated PhoneNumber phone=4;
}

当然这里的protobuf的秒数文件.proto也是有版本语法限制的,比如protoBuf3中没有required和optional。

每个消息类型拥有一个或多个特定的数字字段,每个字段拥有一个名字和一个值类型。值类型可以是数字(整数或浮点)、布 尔型、字符串、原始字节或者其他ProtocolBuffer类型,还允许数据结构的分级。

上面的message就类似于类,下面是属性。

required在protobuf2代表是必填的,optional在protobuf2中代表是可选的。repeated代表重复字段,类似于list。

下面的enum代表是枚举。

下面的message是在上面Person的里面,代表内部类。default代表默认值。

需要注意的是这里的=1,=2等都不是对其进行赋值,而是对属性做一个唯一标志。

编译描述文件

一旦你定义了自己的报文格式(message),你就可以运行ProtocolBuffer编译器,将你的 .proto 文件编译成特定语言的类。这些类提供了简单的方法访问每个字段(像是 query() 和set_query()),像是访问类的方法一样将结构串行化或反串行化。

编译器下载地址:

https://github.com/protocolbuffers/protobuf/releases

选择指定的操作系统的指定protobuf版本的protoc编译器进行下载

 

ProtoBuf的介绍以及在Java中使用protobuf将对象进行序列化与反序列化_protobuf

这里操作系统是Windows64位并且在下面要使用的protobuf的版本是3.13

所以这里下载对应的版本

 

ProtoBuf的介绍以及在Java中使用protobuf将对象进行序列化与反序列化_protobuf_02

将其下载到电脑上某路径下解压

 

ProtoBuf的介绍以及在Java中使用protobuf将对象进行序列化与反序列化_数据_03

后续就可以使用protoc.exe对proto文件进行编译。

为了使用方便,这里将protoc.exe添加进环境变量

 

ProtoBuf的介绍以及在Java中使用protobuf将对象进行序列化与反序列化_描述文件_04

然后打开cmd,输入protoc后回车,会输出编译的提示命令则是成功

 

 

ProtoBuf的介绍以及在Java中使用protobuf将对象进行序列化与反序列化_protobuf_05

Java中使用ProtoBuf序列化和反序列化示例

新建项目并引入依赖

打开IDEA-新建一个gradle项目,当然你也可以新建一个Maven项目。

这里以使用gradle作为依赖管理进行示例。

新建gradle项目后选择Java语言,然后添加protobuf相关的依赖。

来到Maven的中央仓库

https://mvnrepository.com/

搜索protobuf

 

ProtoBuf的介绍以及在Java中使用protobuf将对象进行序列化与反序列化_protobuf_06

这两个就是需要引入的依赖。

分别进入两个依赖中选择跟上面的编译的版本一致的版本

 

ProtoBuf的介绍以及在Java中使用protobuf将对象进行序列化与反序列化_描述文件_07

这里是Gradle的依赖,你也可以使用Maven并复制Maven的依赖。

 

ProtoBuf的介绍以及在Java中使用protobuf将对象进行序列化与反序列化_数据_08

找到IDEA中新建的gradle项目的build.gradle将两个依赖添加进去。

dependencies {
    compile (
            [group:'com.google.protobuf', name: 'protobuf-java', version: '3.13.0'],
            [group:'com.google.protobuf', name: 'protobuf-java-util', version: '3.13.0']
    )
}

因为设置了自动导入,所以会在项目中引入Google的相关protobuf的依赖的jar包

 

ProtoBuf的介绍以及在Java中使用protobuf将对象进行序列化与反序列化_protobuf_09

编写proto描述文件

然后在src下新建protobuf目录,在此目录下新建文件Student.proto

 

ProtoBuf的介绍以及在Java中使用protobuf将对象进行序列化与反序列化_java_10

此时IDEA会提示,选择Text即可。

syntax = "proto3";

package com.badao.protobuf;

option optimize_for =SPEED;
option java_package = "com.badao.protobuf";
option java_outer_classname = "DataInfo";

message Student {
    string name = 1;
    int32 age = 2;
    string address = 3;
}

然后将其内容修改如下

这里的syntax代表使用的语法规则是protobuf3

然后下面的package是缺省时的包名,如果下面没有设置java_package则会使用此设置,如果设置了则不会使用。

下面的是一些配置

optimize_for是文件级别的选项,Protocol Buffer定义三种优化级别SPEED/CODE_SIZE/LITE_RUNTIME。缺省情况下是SPEED。

SPEED: 表示生成的代码运行效率高,但是由此生成的代码编译后会占用更多的空间。

然后java_package就是配置的生成代码的包名,

java_outer_classname选项表明想要生成Java类的名称。如果在.proto文件中没有明确的java_outer_classname定义,生成的class名称将会根据.proto文件的名称采用驼峰式的命名方式进行生成。如(foo_bar.proto生成的java类名为FooBar.java)。

这里配置的类名就叫DataInfo。

编译描述文件生成代码

在IDEA中下面的Terminal新建一个终端

 

ProtoBuf的介绍以及在Java中使用protobuf将对象进行序列化与反序列化_描述文件_11

因为已经将protoc编译命令的exe添加进环境变量,所以这里直接使用protoc命令即可。

protoc --java_out=src/main/java src/protobuf/Student.proto

这里--java_out=src/main/java就是设置的要生成代码后存放的位置

后面跟着个空格然后跟的是 proto描述文件的位置

回车后如果没有报错,并且已经在src/main/java/com/badao/protobuf下生成DataInfo类

 

ProtoBuf的介绍以及在Java中使用protobuf将对象进行序列化与反序列化_protobuf_12

则编译成功。

对象数据的序列化与反序列化

在此包下新建一个ProtobuTest类,并编写main方法

package com.badao.protobuf;

import com.google.protobuf.InvalidProtocolBufferException;

public class ProtobufTest {
    public static void main(String[] args) throws InvalidProtocolBufferException {
        DataInfo.Student student = DataInfo.Student.newBuilder()
                .setName("公众号:霸道的程序猿").setAge(100).setAddress("中国").build();
        byte[] bytes = student.toByteArray();

        DataInfo.Student student1 = DataInfo.Student.parseFrom(bytes);
        System.out.println(student1.getName());
        System.out.println(student1.getAge());
        System.out.println(student1.getAddress());
    }
}

注意这里的新建对象并对属性进行赋值时必须采用如上这种方式

DataInfo.Student student = DataInfo.Student.newBuilder()
                .setName("公众号:霸道的程序猿").setAge(100).setAddress("中国").build();

然后将对象进行序列化为字节数组就可以通过

byte[] bytes = student.toByteArray();

将字节数据反序列化为对象就可以通过

DataInfo.Student student1 = DataInfo.Student.parseFrom(bytes);

然后运行该main方法。

 

ProtoBuf的介绍以及在Java中使用protobuf将对象进行序列化与反序列化_java_13


 

 

 

 

 


标签:java,protobuf,proto,DataInfo,Student,Java,序列化
From: https://blog.51cto.com/BADAOLIUMANGQZ/6144515

相关文章

  • Netty中集成Protobuf实现Java对象数据传递
    在上面两篇博客基础上,对于Socket搭建服务端和客户端进行通信以及在Java中Protobuf的使用已经有了初步的理解。那么怎样使用Netty进行服务端和客户端的通信时使用protobuf进......
  • java正则
    正则常见用法(例子来源:hutool文档):Stringcontent="ZZZaaabbbccc中文1234";Patternpattern=Pattern.compile(regex,Pattern.DOTALL);Matchermatcher=pattern.m......
  • #Java程序设计实践
    Java程序设计实践Java训练集1~3总结与心得训练集链接前言:本次训练集1~3主要考察了对java基础语法的掌握,内容包括基础程序的设计,类设计,编程规则的掌握等等,学习的重点在......
  • java学习日记20230320-类变量和类方法
    类变量和类方法static修饰的静态变量或者方法静态变量是类共享的,当class运行时。jdk8之前时放在方法区,静态域,jdk8之后放在堆中,会生成class对象在堆中;在类加载中生成;st......
  • 20.(行为型模式)java设计模式之迭代器模式
    一、什么是迭代器模式(IteratorPattern)   提供—种方法顺序访问一个聚合对象中各个元素,而又无须暴露该对象的内部实现,属于行为型模式。应用场景:   —般来说,迭......
  • 反序列化漏洞 之 CC1链(审计分析)
    反序列化前提1、被序列化和反序列化的类需要实现Serializable序列化接口2、并重写readObject方法,在重写的readObject方法中执行objectInputStream.defaultReadOb......
  • Java之size()>0 和isEmpt()性能考量
    为何要写这篇呢?主要是要纠正一个长期以来的误区:size()>0一定比isEmpt()性能差。以下内容是社区里的结论:方法一(数据量大,效率低):if(list!=null&&list.size()>0){}方法......
  • BDD之Java Testing with Spock
    为何会专门写这篇BDD呢?之前我发表过一篇《代码重构之TDD的思考》,有童靴联系到我,探讨之余,感觉这几年集成化方面的测试方案产出太少了,优秀的也太少了。今天带大家了解一个新东......
  • Java运算符
    Java运算符Java运算符有:算术运算符、关系运算符、位运算符、逻辑运算符、赋值运算符、其他运算符算术运算符A=10,B=20操作符描述例子+加法,运算符两侧的值相加......
  • 【Javaweb】html frame标签的使用 | 导航栏右侧内容的实现
    问题的产生:是我和同伴做了一个导航栏,但是我们不知道怎么实现右侧内容的切换    然后我们查了很多资料,但是有一些是垂直的,但是就如图可见,我们是水平的,那么怎么实......