文章目录
- 前言
- Protobuf编解码
- Protobuf入门
- 引入
- 下载`protoc-XXXX-win64.zip`
- idea插件安装
- 编写.proto文件
- 生成Java文件
- .proto文件生成java文件误区
- 测试Protobuf
前言
笔者之前没有接触过Protobuf,第一次使用还是比较复杂,同时网络上没有系统的教程参考,这里困扰了很久,ε=(´ο`*)))唉。
包括一些插件的使用,网上有很多不同的方式,笔者在第一次接触的时候分不清楚,导致混合一起使用。下文会讲清楚
Protobuf需要根据.proto生成文件,笔者使用idea的插件进行,下文有截图。
Protobuf编解码
Protobuf是一个灵活、高效、结构化的数据序列化框架,相比于XML等传统的序列化工具,它更小、更快、更简单。
Protobuf入门
引入
使用maven引入
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
<version>3.14.0</version>
</dependency>
这里推荐使用最新版本,笔者写此文章时,最新的版本是3.14.0。
如果不使用最新版本,可能会导致生成的java文件中 UnusedPrivateParameter
类找不到。
如果出现这种问题请参考:
下载protoc-XXXX-win64.zip
下载地址:https://github.com/protocolbuffers/protobuf/releases
解压后获得protoc.exe
。
配置环境变量,笔者配置没有成功。使用方法2
将protoc.exe
复制到C:\Windows\System32
验证安装,出现以下情况即为安装成功。
idea插件安装
编写.proto文件
笔者是参照《netty权威指南(第2版)》编写的.proto文件。书中使用的是proto2语法, 笔者这里使用proto3语法。给大家做参考,具体的proto3语法笔者也不是很清楚,可以参照官网。
syntax = "proto3";
package netty;
option java_package = "com.wy.protobuftest";
option java_outer_classname = "SubscribeReqProto";//生成的数据访问类的类名
message SubscribeReq {
int32 subReqId = 1;
string userName = 2;
string productName = 3;
string address = 4;
}
syntax = "proto3";
package netty;
option java_package = "com.wy.protobuftest";
option java_outer_classname = "SubscribeRespProto";//生成的数据访问类的类名
message SubscribeResp {
int32 subReqId = 1;
string respCode = 2;
string desc = 3;
}
生成Java文件
插件完成之后在.proto文件上右键,会出现以下选线,选择 quick gen protobuf here 生成文件即可。
默认生成文件是py
的。如果想要生成java文件,则需要一些设置,笔者查找了很多博客,都没有相关的信息,最终笔者在插件的官网找到了一些简单说明,虽然不够详细,但是也足够入门。官网链接:https://plugins.jetbrains.com/plugin/11423-genprotobuf
然后再重新生成文件,就得到了java类
笔者大概翻阅了一下,生成类看起来比较复杂。
.proto文件生成java文件误区
这里想说明一下笔者在学习时的一个误区,如果按照笔者的方式进行,这里生成文件已经完全没问题了,如果UnusedPrivateParameter
类找不到,请升级版本,开头有提到。
最开始笔者参考了很多博客,大多使用了Protobuf Support插件,而且使用了protobuf-maven-plugin这个maven插件。笔者按照这种方式并没有成功,此种方法可以参考文章 :
而按照笔者这种方式,不需要引入很多的maven依赖,也不需要使用maven插件,笔者认为这是一种简单快速的方式。
测试Protobuf
编写测试类,对生成的Protobuf进行测试。
package com.wy.protobuftest;
import com.google.protobuf.InvalidProtocolBufferException;
import java.util.ArrayList;
import java.util.List;
/**
* @ClassName ProtobufTest
* @Description TODO
* @Author Wang Yue
* @Date 2021/2/16 19:44
*/
public class ProtobufTest {
private static byte[] encode(SubscribeReqProto.SubscribeReq req) {
return req.toByteArray();
}
private static SubscribeReqProto.SubscribeReq decode(byte[] body) throws InvalidProtocolBufferException {
return SubscribeReqProto.SubscribeReq.parseFrom(body);
}
private static SubscribeReqProto.SubscribeReq createSubscribeReq() {
SubscribeReqProto.SubscribeReq.Builder builder = SubscribeReqProto.SubscribeReq.newBuilder();
builder.setSubReqId(1);
builder.setUserName("WY");
builder.setProductName("Netty Book");
builder.setAddress("shanghai");
return builder.build();
}
public static void main(String[] args) throws InvalidProtocolBufferException {
SubscribeReqProto.SubscribeReq req = createSubscribeReq();
System.out.println("编码前: " + req.toString());
byte[] encode = encode(req);
System.out.println("编码后: " + encode.toString());
SubscribeReqProto.SubscribeReq decode = decode(encode);
System.out.println("重新解码: " + decode.toString());
}
}
写测试类的过程中可以看到,protobuf在生成java文件时 :
syntax = "proto3";
package netty;
option java_package = "com.wy.protobuftest";
option java_outer_classname = "SubscribeReqProto";//生成的数据访问类的类名
message SubscribeReq {
int32 subReqId = 1;
string userName = 2;
string productName = 3;
string address = 4;
}
java_outer_classname
对应的是java类文件名,而我们真正关注的 SubscribeReq
,则是以内部类的方式进行组织的。
最后,贴一下测试结果
可以看到编码后的数据量很小,重新解码后,得到的数据和编码前的一致。