原创

JAVA中使用Google Protobuf

1.介绍

ProtoBuf 是一套接口描述语言(IDL)和相关工具集
google protobuf是一个灵活的、高效的用于序列化数据的协议。相比较XML和JSON格式,protobuf更小、更快、更便捷。google protobuf是跨语言的,并且自带了一个编译器(protoc),只需要用它进行编译,可以编译成Java、python、C++、C#、Go等代码,然后就可以直接使用,不需要再写其他代码,自带有解析的代码,目前protoBuf对主流的编程语言都提供了支持,非常方便的进行序列化和反序列化
使用之前建议先学习一下ProtoBuf语法

特点

  • 平台无关、语言无关
  • 二进制、数据自描述
  • 提供了完整详细的操作API
  • 高性能 比xml要快20-100倍
  • 尺寸小 比xml要小3-10倍 高可扩展性
  • 数据自描述、前后兼容

2.下载使用

1.下载protobuf

下载地址

pom.xml

        <!-- https://mvnrepository.com/artifact/com.google.protobuf/protobuf-java -->
        <dependency>
            <groupId>com.google.protobuf</groupId>
            <artifactId>protobuf-java</artifactId>
            <version>3.9.0</version>
        </dependency>

2.编译安装

ZBMAC-C02WD12BH:protobuf-3.9.0 lishihao$ ./configure --prefix=/usr/local/bin
ZBMAC-C02WD12BH:protobuf-3.9.0 lishihao$ make
ZBMAC-C02WD12BH:protobuf-3.9.0 lishihao$ make check
....
PASS: protobuf-lite-arena-test
PASS: no-warning-test
============================================================================
Testsuite summary for Protocol Buffers 3.9.0
============================================================================
# TOTAL: 7
# PASS:  7
# SKIP:  0
# XFAIL: 0
# FAIL:  0
# XPASS: 0
# ERROR: 0
============================================================================

ZBMAC-C02WD12BH:protobuf-3.9.0 lishihao$ make install

.....
 /usr/local/bin/gmkdir -p '/usr/local/include/google/protobuf/compiler/ruby'
 /usr/local/bin/ginstall -c -m 644  google/protobuf/compiler/ruby/ruby_generator.h '/usr/local/include/google/protobuf/compiler/ruby'
 /usr/local/bin/gmkdir -p '/usr/local/include/google/protobuf/compiler/csharp'
 /usr/local/bin/ginstall -c -m 644  google/protobuf/compiler/csharp/csharp_generator.h google/protobuf/compiler/csharp/csharp_names.h '/usr/local/include/google/protobuf/compiler/csharp'
 /usr/local/bin/gmkdir -p '/usr/local/include/google/protobuf/compiler/js'
 /usr/local/bin/ginstall -c -m 644  google/protobuf/compiler/js/js_generator.h google/protobuf/compiler/js/well_known_types_embed.h '/usr/local/include/google/protobuf/compiler/js'

make install之后就是安装成功了

3.配置环境变量

/usr/local/bin 已经在我的环境变量了,不在的或者定义其他目录的需要重新配置
使用protoc生成java代码

4. .proto文件

  • .proto文件是protobuf一个重要的文件,它定义了需要序列化数据的结构。
  • 使用protobuf的3个步骤

1.在.proto文件中定义消息格式

2.用protobuf编译器编译.proto文件

syntax = "proto3";

package protocol;

option java_package = "com.fireflyi.gn.gerant.common.protobuf";
option java_outer_classname = "GerantReqProtobuf";

/**
 * 聊天类型
 */
enum ChatType {
    CHAT_TYPE_PUBLIC = 0;//群聊
    CHAT_TYPE_PRIVATE = 1;//私聊
}

message GerantReqProtocol {
    int64 time = 1;//消息发送时间
    ChatType type = 2; //聊天类型
    string reqMsg = 3;
    int32 reqId = 4; //目标用户id,
}

"运行生成GerantReqProtobuf对象"
ZBMAC-C02WD12BH:protobuf lishihao$ protoc --java_out=./ GerantReqProto.proto

message 与 javaouterclassname不能相同

生成对应的java对象

public final class GerantReqProtobuf {
  private GerantReqProtobuf() {}
  public static void registerAllExtensions(
      com.google.protobuf.ExtensionRegistryLite registry) {
  }

  public static void registerAllExtensions(
      com.google.protobuf.ExtensionRegistry registry) {
    registerAllExtensions(
        (com.google.protobuf.ExtensionRegistryLite) registry);
  }
  ........

  public static com.google.protobuf.Descriptors.FileDescriptor
      getDescriptor() {
    return descriptor;
  }
  private static  com.google.protobuf.Descriptors.FileDescriptor
      descriptor;
  static {
    String[] descriptorData = {
      "\n\024GerantReqProto.proto\022\010protocol\"b\n\021Gera" +
      "ntReqProtocol\022\014\n\004time\030\001 \001(\003\022 \n\004type\030\002 \001(" +
      "\0162\022.protocol.ChatType\022\016\n\006reqMsg\030\003 \001(\t\022\r\n" +
      "\005reqId\030\004 \001(\005*7\n\010ChatType\022\024\n\020CHAT_TYPE_PU" +
      "BLIC\020\000\022\025\n\021CHAT_TYPE_PRIVATE\020\001B;\n&com.fir" +
      "eflyi.gn.gerant.common.protobufB\021GerantR" +
      "eqProtobufb\006proto3"
    };
    descriptor = com.google.protobuf.Descriptors.FileDescriptor
      .internalBuildGeneratedFileFrom(descriptorData,
        new com.google.protobuf.Descriptors.FileDescriptor[] {
        });
    internal_static_protocol_GerantReqProtocol_descriptor =
      getDescriptor().getMessageTypes().get(0);
    internal_static_protocol_GerantReqProtocol_fieldAccessorTable = new
      com.google.protobuf.GeneratedMessageV3.FieldAccessorTable(
        internal_static_protocol_GerantReqProtocol_descriptor,
        new String[] { "Time", "Type", "ReqMsg", "ReqId", });
  }

  // @@protoc_insertion_point(outer_class_scope)

3.用Java的protobuf API来写或者读消息

/**
 * @author by fireflyi (6025606@qq.com)
 * @website https://www.fireflyi.com
 * @date 2019/7/19
 * DESC TODO
 */
public class PtbTest {

    /**
     * 编码GerantReqProtobuf.GerantReqProtocol对象
     * @param req
     * @return
     */
    private static byte[] encode(GerantReqProtobuf.GerantReqProtocol req) {
        return req.toByteArray();
    }

    /**
     * 解码GerantReqProtobuf.GerantReqProtocol对象
     * @param body
     * @return
     * @throws InvalidProtocolBufferException
     */
    private static GerantReqProtobuf.GerantReqProtocol decode(byte[] body) throws InvalidProtocolBufferException {
        return GerantReqProtobuf.GerantReqProtocol.parseFrom(body);
    }

    /**
     * 创建GerantReqProtobuf.GerantReqProtocol对象
     * @return
     */
    private static GerantReqProtobuf.GerantReqProtocol crete(){
        GerantReqProtobuf.GerantReqProtocol.Builder builder = GerantReqProtobuf.GerantReqProtocol.newBuilder();
        builder.setType(GerantReqProtobuf.ChatType.CHAT_TYPE_PUBLIC);
        builder.setReqMsg("hello protobuf");
        return builder.build();
    }

    public static void main(String[] args) throws InvalidProtocolBufferException {
        GerantReqProtobuf.GerantReqProtocol ptb = crete();
        GerantReqProtobuf.GerantReqProtocol ptb2 = decode(encode(ptb));
        System.out.println("ptb对象->" + ptb.toString());
        System.out.println("编码在解码ptb对象->" + ptb2);
        System.out.println(ptb.equals(ptb2));
        System.out.println(ptb.hashCode());
        System.out.println(ptb2.hashCode());
    }

}

运行结果

ptb对象->reqMsg: "hello protobuf"
编码在解码ptb对象->reqMsg: "hello protobuf"
true
1788658989
1788658989

4. 在netty中使用

在netty中使用protobuf

正文到此结束
本文目录