Protocol Buffer的使用

大家对于json xml这两个数据传输协议都比较熟悉,但是说起谷歌的protocol buffer,可能大家很多人没有接触过。在此之前,先介绍下数据传输协议中经常会听到的两个名词。

序列化:将数据结构或对象转化为二进制字符串的过程。反序列化:将二进制字符串转化为数据结构或对象的过程。

xml是用标签来存储数据,json使用独立于编程语言的文本存储和表示数据,而protocol buffer是使用通过序列化来完成数据的传输。从这一点上看,protocol buffer相比于前两者更小、更快,更符合数据传输量大的场景,使用和维护起来也很简单。下面介绍protobuf在java下的使用方法。

一、protocol buffer编译器安装

protocol buffer提供了数据结构和对象的语法定义,其源文件为.proto后缀,通过编译器可以自动生成相应语言的序列化对象工具。

github下载地址:https://github.com/google/protobuf

如果是windows环境,还需要下载protoc.exe,并复制到protobuf目录下的src文件夹下。下载地址:https://download.csdn.net/download/antgan/9593735

编辑系统环境变量PATH,将protoc.exe的存放目录(即protobuf下的src)添加到PATH中。

二、使用IDEA新建maven项目

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">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.neymar</groupId>
    <artifactId>protobuf-test</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
        <dependency>
            <groupId>com.google.protobuf</groupId>
            <artifactId>protobuf-java</artifactId>
            <version>3.4.0</version>
        </dependency>
    </dependencies>

</project>

整个项目的目录如下


proto存放.proto文件,main调用protobuf编译器,java存放生成的java文件

三、编辑proto文件

protobuf的语法跟java定义类的语法很相似,下一节将会详细介绍,大家可以先看一个实例

option java_outer_classname = "StudentEntity";
message Student {
  required int32 id = 1;
  required string name = 2;
  optional string nickname = 3;
}

java_outer_classname是输出的java文件名,message定义了一个数据结构,required和optional都是修饰符,前者指该字段是必须有且一个,后者指有0个或1个,等号后边的数字是对字段进行编号。

四、编译proto文件

编译可以通过java main方法来执行cmd命令,或者直接在cmd输入相应的命令

cmd中的命令为protoc.exe -I=源地址 --java_out=输出地址 源地址/xxx.proto

package com.neymar.prototest;

import java.io.IOException;

public class main {
    public static void main(String[] args) {
        String protoFile = "student-entity.proto";//
        String strCmd = "C:/Program Files/protobuf-master/src/protoc.exe -I=./src/main/java/com/neymar/prototest/proto --java_out=./src/main/java/com/neymar/prototest/java ./src/main/java/com/neymar/prototest/proto/"+ protoFile;
        try {
            Runtime.getRuntime().exec(strCmd);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
五、序列化及反序列化
package com.neymar.prototest;

import com.google.protobuf.InvalidProtocolBufferException;
import com.neymar.prototest.java.StudentEntity;

public class main {
    public static void main(String[] args) throws InvalidProtocolBufferException {
        StudentEntity.Student.Builder builder= StudentEntity.Student.newBuilder();
        builder.setId(1);
        builder.setName("neymar");
        builder.setNickname("ney");
        StudentEntity.Student student = builder.build();
        System.out.println("序列化前 :"+ student.toString());

        System.out.println("===========序列化后的字符==========");
        for(byte b : student.toByteArray()){
            System.out.print(b);
        }
        System.out.println();
        System.out.println("================================");
        System.out.println();

        //Byte[]就是序列化后的字符串,反序列化成Student类
        byte[] byteArray =student.toByteArray();
        StudentEntity.Student stu = StudentEntity.Student.parseFrom(byteArray);
        System.out.println("反序列化后:" +stu.toString());
    }
}

输出截图


六、对比总结

相对于上面的例子,如果我们把相同的对象使用json来进行传输,其内容为{"id":1,"name":"neymar","nickname":"ney"}。我们可以总结下protobuf相比于json的优势:

  1. 使用二进制来存储对象数据,体积小,序列化速度快,传输速度快
  2. 使用简单,多平台只用管理维护同一套proto文件,可以跨平台跨语言使用
  3. protobuf使用非明文传输,数据安全上优于json
  4. protobuf对于数据结构的定义可以兼容更多的数据类型,例如数据结构的嵌套使用、枚举等(protobuf的具体语法规则在将在另一篇博客中进行介绍)
  5. RPC的数据传输适合使用protobuf

但在下面的情况中,使用json会比protobuf更好:

  1. protobuf由于是二进制传输,可读性相比于json,是远远比不上的
  2. 服务器与WEB浏览器的通信使用json比使用protocol要好得多
阅读更多 登录后自动展开
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页