文章目录

  • 前言
  • 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

Android解析proto文件_netty

解压后获得protoc.exe

配置环境变量,笔者配置没有成功。使用方法2

protoc.exe复制到C:\Windows\System32

验证安装,出现以下情况即为安装成功。

Android解析proto文件_java_02

idea插件安装

Android解析proto文件_java_03

编写.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 生成文件即可。

Android解析proto文件_java文件_04


默认生成文件是py的。如果想要生成java文件,则需要一些设置,笔者查找了很多博客,都没有相关的信息,最终笔者在插件的官网找到了一些简单说明,虽然不够详细,但是也足够入门。官网链接:https://plugins.jetbrains.com/plugin/11423-genprotobuf

Android解析proto文件_netty_05


Android解析proto文件_java_06

然后再重新生成文件,就得到了java类

Android解析proto文件_java文件_07

笔者大概翻阅了一下,生成类看起来比较复杂。

.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,则是以内部类的方式进行组织的。

最后,贴一下测试结果

Android解析proto文件_maven_08


可以看到编码后的数据量很小,重新解码后,得到的数据和编码前的一致。