1.1 protobuff简介
如果做过web开发,那一定接触过json,如果没接触过json,这边不介意学习protobuff,对你来说没有任何意义
protobuff是什么?就是一组规则,基于字节流的数据交换规则。而因为要降低传输的信息量,所以对于服务器双方都必须要在事先准备一个解编码器来对数据进行压缩传输。
而这一套解编码器就是protobuff的精髓。
1.2 protobuff模型
如果你学过mvc,你会更容易理解,什么是模型。简单来说,一个模型就是描述一个对象的字段的集合。所以一般的序列化和反序列就是针对于模型来说的。序列化是将动态数据持久化的过程,而反序列化就是其逆过程。
如果你学习过java,那你一定会非常熟悉,比如我定义了一个Person的对象p1,我对立面的字段比如名字,身份证号,家庭住址进行了序列化,就是将其转化成一堆二进制流,并用一个文本存储或者存储到数据库之类的。当然,为了让“人”更加容易理解,这一堆的二进制流通常表现形式是字符形式,也就是进行了比如Utf-8的这种编码,让你看到的是一组文字。然而事实上,它就是一堆二进制。
这就是序列化。而动态数据,就是你的这个Person对象,当你使用new关键字存储到堆中时,就可以认为,这个person对象是一个动态数据。
那么protobuff模型则是一对序列化和反序列化的合集。
你可以将它和json模型进行类比
json模型序列化后是一组规则的字符串,当然,也因此,其信息冗余是非常巨大的
json模型反序列化后则是一个对象,比如person的一个生成在堆里面的动态数据
那么protobuff也可以这样去理解。
对象,是通过new 一个类产生的,所以,我们将对象和类模板区分开来。之后描述的模型就是类模板。
定义一个类模板非常简单,就是你日常写的java类或者是c#类:
public class TreeNode {
public TreeNode left;
public TreeNode right;
public String val;
public TreeNode(String val){
this.val = val;
}
}
上述就是一个模型,一个类模板。
你可以在同一个进程里面肆无忌惮的用这个模型进行数据交换。
但是,假如你希望通过socket进行数据传输,那么就无法使用这个模型直接传输,你需要将它进行序列化,通过二进制在物理线上进行传输。
那么序列化就有很多种选择了,你可以序列化成json对象,当然也可以序列化成protobuff对象
如果你学过霍夫曼编码,你会理解什么叫信息冗余,这里我不做赘述,毕竟,这是一个非常大的课题。
这个系列探究的是序列化成protobuf,一切都和protobuf有关
现在约定,protobuf未序列化时,称为p模型,序列化后称为序列化p模型
同样的,json为序列化时,称为j模型,序列化后称为序列化j模型
protobuf之所以比起json要麻烦,就是它的p模型的定义比起j模型要复杂得多
j模型的定义:
public class TreeNode {
public TreeNode left;
public TreeNode right;
public String val;
}
嗯,你没看错,就是一个原生的类就行了,非常简单
但是你要定义一个p模型,那么手动打字也不是不行,但通常情况下需要借助protobuf的代码生成器,这也是为什么看protobuf的教程云里雾里的
1.3 protobuff模型生成器(java环境下,基于maven)
现在我要生成一个Person的对象
分以下几步:
1.在src/main下建立proto文件夹
2.在proto文件夹下创建一个Person.proto的文件(txt类型),利用protobuff语法定义一个protobuff生模型,简称ps模型,
3.通过maven添加相关依赖
4.利用Plugins的protobuf的编译器将该Persion.proto转化成.java对象
以下是截图:
步骤1和2:
syntax = "proto3";
message SearchRequest {
string query = 1;
int32 page_number = 2;
int32 result_per_page = 3;
}
语法啥的,都没有进行研究,不急,一步一步来
步骤3:
在pom里面添加以下依赖:
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<grpc.version>1.20.0</grpc.version>
<os.plugin.version>1.5.0.Final</os.plugin.version>
<protobuf.plugin.version>0.5.1</protobuf.plugin.version>
<protoc.version>3.5.1</protoc.version>
</properties>
<dependencies>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-protobuf</artifactId>
</dependency>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-stub</artifactId>
</dependency>
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
<version>3.5.1</version>
</dependency>
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java-util</artifactId>
<version>3.7.1</version>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-bom</artifactId>
<version>${grpc.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<extensions>
<extension>
<groupId>kr.motd.maven</groupId>
<artifactId>os-maven-plugin</artifactId>
<version>${os.plugin.version}</version>
</extension>
</extensions>
<plugins>
<plugin>
<groupId>org.xolstice.maven.plugins</groupId>
<artifactId>protobuf-maven-plugin</artifactId>
<version>${protobuf.plugin.version}</version>
<configuration>
<protocArtifact>com.google.protobuf:protoc:${protoc.version}:exe:${os.detected.classifier}
</protocArtifact>
<pluginId>grpc-java</pluginId>
<pluginArtifact>io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:${os.detected.classifier}
</pluginArtifact>
<attachProtoSources>false</attachProtoSources>
<clearOutputDirectory>false</clearOutputDirectory>
//指定输出路径
<outputDirectory>${basedir}/src/main/java</outputDirectory>
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>compile-custom</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
</build>
步骤4:
编译成功后控制台自动提示:
然后就产生了T2这个对象:
1.4 为什么说Protoc与语言无关?
其实从这个章节的学习我们可以很清晰的发现,我们只需要定义一个xx.proto文件,就能够描述一个模型,而由不同语言已经写好的这样一个库去进行翻译。所以我们说它是一种与语言无关的交换协议。
你可以参考java的跨平台的原理,protobuff就是一种跨语言进行数据交换的协议,入门可能麻烦一点,但用起来是真的爽。