文档章节

Google Protobuf编解码(序列化/反序列化)框架

兴趣使然的程序员
 兴趣使然的程序员
发布于 2017/04/05 14:07
字数 997
阅读 177
收藏 0

编码/解码在Java中又称序列化/反序列化,Java本身的序列化反序列化技术生成的二进制码流太大,且转化效率低下,一般不适用于远程跨节点调用的编码框架。

Protobuf全称Protocol Buffers,由谷歌开源而来,特点如下:

  1. 码流小、效率高
  2. 语言平台无关,不只Java可以用,C++、python亦可
  3. 使用数据描述文件,可自动生成代码
  4. 和Facebook Thirft对比,Protobuf并不需要完全在开始就完全定义好全部结构,而可以在后期extends之前的结构,并且仍然可以读取之前结构编码的信息

使用步骤:

  1. 编写.proto类定义文件
  2. 通过提供的编译器产生对应的Java类
  3. 使用提供的API读写信息

1、编写.proto类定义文件

package tutorial;

option java_package = "com.example.tutorial";
option java_outer_classname = "AddressBookProtos";

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 phones = 4;
}

message AddressBook {
  repeated Person people = 1;
}

文件说明:

  1. package用于区分同名文件,在java_package缺省时,就是产生的bean的包
  2. java_outer_classname指定包含文件中定义的所有类的类,如果缺省,会自动将.proto文件名设为类名
  3. message定义一个类,message中可以包含message
  4. 每个属性后面的 =1、=2等数字是在二进制化数据时,属性的“唯一标识”,在每个message中独立编号

支持的修饰符:

  1. required:标识必须被提供的字段,如果required字段的值没有被提供,编码解码时都会跑出异常;
  2. optional:标识可以提供或不提供的字段,如果不提供,则返回默认值。默认值和java中相似,但是“子message”的字段会全部为空。默认值也可以用[default = value]进行设置;
  3. repeated:标识ArrayList
  4. 每个属性后面的 =1、=2等数字,注意0-15比之后的数字再序列化时少一个字节,固0-15一般用在required和repeated字段上

支持的数据类型:boolint32floatdoublestringenum 

.proto Type Notes C++ Type Java Type Python Type Go Type
double   double double float *float64
float   float float float *float32
int32 虽然可以有负数,但是效率不高 int32 int int *int32
int64 虽然可以有负数,但是效率不高 int64 long int/long[3] *int64
uint32 无符号整数,只能是正数 uint32 int int/long[3] *uint32
uint64 无符号整数,只能是正数 uint64 long int/long[3] *uint64
sint32 有符号整数,表示负数的效率更高 int32 int int *int32
sint64 有符号整数,表示负数的效率更高 int64 long int/long[3] *int64
fixed32 永远占据4个字节,如果超过256的话,效率更高 uint32 int int *uint32
fixed64 永远占据8个字节,如果超过256的话,效率更高 uint64 long int/long[3] *uint64
sfixed32 永远占据4个字节 int32 int int *int32
sfixed64 永远占据8个字节 int64 long int/long[3] *int64
bool   bool boolean bool *bool
string 字符串必须是UTF-8或者7-bit ASCII。 string String str/unicode *string
bytes   string ByteString str []byte

备注:

[3] Python3中不再有int和long之分,而只有不限长度的整型int。

2、通过提供的编译器产生对应的Java类

2.1、将protoc.exe和对应的.proto文件放到项目所在的java文件夹下

protoc.exe --java_out=.\ .\Request.proto

就可以在上面的proto文件中的java_package描述的位置产生指定的文件

3、使用提供的API读写信息

public class TestSubscribeReqProto {
    /**
     * 1、构建对象
     * @return
     */
    public static SubscribeReqProto.SubscribeReq createSubscribeReq(){
        SubscribeReqProto.SubscribeReq.Builder builder =
                SubscribeReqProto.SubscribeReq.newBuilder();
        builder.setSubReqID(1);
        builder.setUserName("caizhijie");
        builder.setProductName("Yellow Book");
        List<String> address = new ArrayList<>();
        address.add("NanJing YuHuaTai");
        address.add("BeiJing ZhiJinCheng");
        address.add("ShenZhen HongShuLin");
        builder.addAllAddress(address);
        return builder.build();
    }

    /**
     * 2、编码
     * @param req
     * @return
     */
    public static byte[] encode(SubscribeReqProto.SubscribeReq req){
        return req.toByteArray();
    }

    /**
     * 3、解码
     * @param body
     * @return
     * @throws InvalidProtocolBufferException
     */
    public static SubscribeReqProto.SubscribeReq decode(byte[] body) throws InvalidProtocolBufferException {
        return SubscribeReqProto.SubscribeReq.parseFrom(body);
    }

    public static void main(String[] args) throws InvalidProtocolBufferException {
        SubscribeReqProto.SubscribeReq req = createSubscribeReq();
        System.out.println("Before encode : "+req.toString());
        SubscribeReqProto.SubscribeReq req2 = decode(encode(req));
        System.out.println("After encode : "+req2.toString());
        System.out.println("Assert equal : -->" + req2.equals(req));
    }
}

 

© 著作权归作者所有

共有 人打赏支持
兴趣使然的程序员
粉丝 21
博文 112
码字总数 87412
作品 0
深圳
程序员
几种序列化协议(protobuf,xstream,jackjson,jdk,hessian)相关数据

别人的相关测试数据: http://code.google.com/p/thrift-protobuf-compare/wiki/Benchmarking 测试纬度 序列化时间 反序列化时间 bytes大小 测试代码 准备protobuf文件 Message.proto文件代码...

SANSOM
2015/08/20
0
0
Protobuf 作者不建议在 Deno 中使用 Protobuf

0. 背景 我之前在"如何评价ry(Ryan Dahl)的新项目deno?"的回答中曾经写到: 我比较好奇的是 deno 使用了 Protobuf,而没有使用 Mojo。既然目标是要兼容浏览器,却不使用 Mojo... ... 但是从 ...

justjavac
06/27
0
0
Netty with protobuf(一)

Netty with protobuf 这是一篇关于netty和protobuf2的文章,先来介绍一下protobuf的简单使用。网上有很多基本的protobuf的介绍,这里就不在赘述了。 protobuf官网上提供了一个例子,我们就拿...

秋风醉了
2014/07/26
0
0
采用protobuf降低redis的内存使用

Redis的当前数据存储在内存中,由于内存并不象硬盘一样有着很大的空间,对于服务器来说一般只会提供16G或32G内存。所以让Redis使用这些内存存储更多的数据是比较重要的。在使用redis的sampl...

泥水佬
2013/08/19
0
1
基于.NET CORE微服务框架 -谈谈surging 的messagepack、protobuffer、json.net 序列化

1、前言 surging内部使用的是高性能RPC远程服务调用,如果用json.net序列化肯定性能上达不到最优,所以后面扩展了protobuf,messagepack序列化组件,以支持RPC二进制传输. 在这里需要感谢白纸...

fanly11
2017/11/18
0
0

没有更多内容

加载失败,请刷新页面

加载更多

分布式框架spring-session实现session一致性使用问题

前言:项目中使用到spring-session来缓存用户信息,保证服务之间session一致性,但是获取session信息为什么不能再服务层获取? 一、spring-session实现session一致性方式 用户每一次请求都会...

WALK_MAN
11分钟前
1
0
C++ yield()与sleep_for()

C++11 标准库提供了yield()和sleep_for()两个方法。 (1)std::this_thread::yield(): 线程调用该方法时,主动让出CPU,并且不参与CPU的本次调度,从而让其他线程有机会运行。在后续的调度周...

yepanl
18分钟前
0
0
Java并发编程实战(chapter_3)(线程池ThreadPoolExecutor源码分析)

这个系列一直没再写,很多原因,中间经历了换工作,熟悉项目,熟悉新团队等等一系列的事情。并发课题对于Java来说是一个又重要又难的一大块,除非气定神闲、精力满满,否则我本身是不敢随便写...

心中的理想乡
28分钟前
15
0
shell学习之获取用户的输入命令read

在运行脚本的时候,命令行参数是可以传入参数,还有就是在脚本运行过程中需要用户输入参数,比如你想要在脚本运行时问个问题,并等待运行脚本的人来回答。bash shell为此提 供了read命令。 ...

woshixin
55分钟前
1
0
区块链技术中的那些能商用的企业级应用

WEPOWER是一家立陶宛初创企业,旨在改变可再生电力项目的付费方式。WePower公司创始人Nick Martyniuk表示,政府统一收购价的存在推动了全球风能与太阳能市场的发展。因此,他的公司希望帮助那...

问题终结者
今天
2
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部