肿抢 发表于 2025-8-1 20:18:36

高效编解码协议之protobuf协议详解

Protocol Buffers(简称 protobuf)是 Google 开发的 高效二进制序列化工具,用于结构化数据的存储和传输。
核心特性

特性说明跨语言支持支持 Java、C++、Python、Go 等主流语言。高效编解码二进制格式,比 JSON/XML 更小、更快。强类型约束通过 .proto 文件定义数据结构,避免运行时错误。向后兼容支持字段扩展(新增字段不影响旧代码)。使用指南

开发环境


[*]windows
[*]jetbrains idea
[*]maven_3.9.7
[*]jdk_8
[*]protobuf_31.1
安装编译器(protoc)


[*]下载地址: protobuf_v31.1
配置


[*]将下载的压缩包解压出来,新增环境变量protobuf=文件夹路径
[*]编辑环境变量Path,新增%protobuf%\bin
验证

# 打开cmd命令行,执行以下命令
protoc --version

# 输出结果如下,表示安装成功
libprotoc 31.1定义数据结构


[*]新建person.proto文件
// person.proto
syntax = "proto3";

message Person {
string name = 1;
int32 id = 2;
repeated string emails = 3;
}编译

手动执行命令

# 打开cmd命令行,切换到person.proto文件目录下,执行以下命令
protoc --java_out=./ ./person.proto

# 当前目录下会生成PersonOuterClass.java文件
# 将PersonOuterClass.java复制到对应项目目录就可以使用了
# PersonOuterClass.java默认没有package路径,需要手动加一下maven插件编译


[*]在pom.xml中加入以下代码,执行maven的clean compile
<build>
<plugins>
    <plugin>
      <groupId>org.xolstice.maven.plugins</groupId>
      protobuf-maven-plugin</artifactId>
      <version>0.6.1</version>
      <executions>
      <execution>
          <goals>
            <goal>compile</goal>
          </goals>
      </execution>
      </executions>
      <configuration>
      
      <protocExecutable>protoc</protocExecutable>
      
      
      </configuration>
    </plugin>
</plugins>
</build>

[*]插件默认读取文件夹/src/main/proto下的proto文件去编译
[*]在文件夹target/generated-sources/protobuf/java下会生成对应pojo的protobuf操作类
注意:

[*]若执行protoc命令之后idea报如下错误:Module 'my-test' production: java.lang.ClassCastException: class org.jetbrains.jps.builders.java.dependencyView.TypeRepr$PrimitiveType cannot be cast to class org.jetbrains.jps.builders.java.dependencyView.TypeRepr$ClassType (org.jetbrains.jps.builders.java.dependencyView.TypeRepr$PrimitiveType and org.jetbrains.jps.builders.java.dependencyView.TypeRepr$ClassType are in unnamed module of loader java.net.URLClassLoader @2f2c9b19)。则清除一下idea的缓存,然后执行rebuild
[*]若idea的terminal或者maven执行compile的时候报错未找到protoc命令,则可以在terminal中执行以下命令排查idea是否读取到最新的Path。若打印的Path值没有protoc的路径,则重启一下电脑。
# terminal中使用的是powershell的话执行
echo $env:path

# terminal中使用的是cmd的话执行
echo %path%编译结果示例

// Generated by the protocol buffer compiler.DO NOT EDIT!
// NO CHECKED-IN PROTOBUF GENCODE
// source: person.proto
// Protobuf Java Version: 4.31.1

@com.google.protobuf.Generated
public final class PersonOuterClass {
private PersonOuterClass() {}
static {
    com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion(
      com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC,
      /* major= */ 4,
      /* minor= */ 31,
      /* patch= */ 1,
      /* suffix= */ "",
      PersonOuterClass.class.getName());
}
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 interface PersonOrBuilder extends
      // @@protoc_insertion_point(interface_extends:Person)
      com.google.protobuf.MessageOrBuilder {

    /**
   * string name = 1;
   * @return The name.
   */
    java.lang.String getName();
    /**
   * string name = 1;
   * @return The bytes for name.
   */
    com.google.protobuf.ByteString
      getNameBytes();

    /**
   * int32 id = 2;
   * @return The id.
   */
    int getId();

    /**
   * repeated string emails = 3;
   * @return A list containing the emails.
   */
    java.util.List<java.lang.String>
      getEmailsList();
    /**
   * repeated string emails = 3;
   * @return The count of emails.
   */
    int getEmailsCount();
    /**
   * repeated string emails = 3;
   * @param index The index of the element to return.
   * @return The emails at the given index.
   */
    java.lang.String getEmails(int index);
    /**
   * repeated string emails = 3;
   * @param index The index of the value to return.
   * @return The bytes of the emails at the given index.
   */
    com.google.protobuf.ByteString
      getEmailsBytes(int index);
}
/**
   * Protobuf type {@code Person}
   */
public static final class Person extends
      com.google.protobuf.GeneratedMessage implements
      // @@protoc_insertion_point(message_implements:Person)
      PersonOrBuilder {
private static final long serialVersionUID = 0L;
    static {
      com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion(
      com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC,
      /* major= */ 4,
      /* minor= */ 31,
      /* patch= */ 1,
      /* suffix= */ "",
      Person.class.getName());
    }
    // Use Person.newBuilder() to construct.
    private Person(com.google.protobuf.GeneratedMessage.Builder<?> builder) {
      super(builder);
    }
    private Person() {
      name_ = "";
      emails_ =
          com.google.protobuf.LazyStringArrayList.emptyList();
    }

    public static final com.google.protobuf.Descriptors.Descriptor
      getDescriptor() {
      return PersonOuterClass.internal_static_Person_descriptor;
    }

    @java.lang.Override
    protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
      internalGetFieldAccessorTable() {
      return PersonOuterClass.internal_static_Person_fieldAccessorTable
          .ensureFieldAccessorsInitialized(
            PersonOuterClass.Person.class, PersonOuterClass.Person.Builder.class);
    }

    public static final int NAME_FIELD_NUMBER = 1;
    @SuppressWarnings("serial")
    private volatile java.lang.Object name_ = "";
    /**
   * string name = 1;
   * @return The name.
   */
    @java.lang.Override
    public java.lang.String getName() {
      java.lang.Object ref = name_;
      if (ref instanceof java.lang.String) {
      return (java.lang.String) ref;
      } else {
      com.google.protobuf.ByteString bs =
            (com.google.protobuf.ByteString) ref;
      java.lang.String s = bs.toStringUtf8();
      name_ = s;
      return s;
      }
    }
    /**
   * string name = 1;
   * @return The bytes for name.
   */
    @java.lang.Override
    public com.google.protobuf.ByteString
      getNameBytes() {
      java.lang.Object ref = name_;
      if (ref instanceof java.lang.String) {
      com.google.protobuf.ByteString b =
            com.google.protobuf.ByteString.copyFromUtf8(
                (java.lang.String) ref);
      name_ = b;
      return b;
      } else {
      return (com.google.protobuf.ByteString) ref;
      }
    }

    public static final int ID_FIELD_NUMBER = 2;
    private int id_ = 0;
    /**
   * int32 id = 2;
   * @return The id.
   */
    @java.lang.Override
    public int getId() {
      return id_;
    }

    public static final int EMAILS_FIELD_NUMBER = 3;
    @SuppressWarnings("serial")
    private com.google.protobuf.LazyStringArrayList emails_ =
      com.google.protobuf.LazyStringArrayList.emptyList();
    /**
   * repeated string emails = 3;
   * @return A list containing the emails.
   */
    public com.google.protobuf.ProtocolStringList
      getEmailsList() {
      return emails_;
    }
    /**
   * repeated string emails = 3;
   * @return The count of emails.
   */
    public int getEmailsCount() {
      return emails_.size();
    }
    /**
   * repeated string emails = 3;
   * @param index The index of the element to return.
   * @return The emails at the given index.
   */
    public java.lang.String getEmails(int index) {
      return emails_.get(index);
    }
    /**
   * repeated string emails = 3;
   * @param index The index of the value to return.
   * @return The bytes of the emails at the given index.
   */
    public com.google.protobuf.ByteString
      getEmailsBytes(int index) {
      return emails_.getByteString(index);
    }

    private byte memoizedIsInitialized = -1;
    @java.lang.Override
    public final boolean isInitialized() {
      byte isInitialized = memoizedIsInitialized;
      if (isInitialized == 1) return true;
      if (isInitialized == 0) return false;

      memoizedIsInitialized = 1;
      return true;
    }

    @java.lang.Override
    public void writeTo(com.google.protobuf.CodedOutputStream output)
                        throws java.io.IOException {
      if (!com.google.protobuf.GeneratedMessage.isStringEmpty(name_)) {
      com.google.protobuf.GeneratedMessage.writeString(output, 1, name_);
      }
      if (id_ != 0) {
      output.writeInt32(2, id_);
      }
      for (int i = 0; i < emails_.size(); i++) {
      com.google.protobuf.GeneratedMessage.writeString(output, 3, emails_.getRaw(i));
      }
      getUnknownFields().writeTo(output);
    }

    @java.lang.Override
    public int getSerializedSize() {
      int size = memoizedSize;
      if (size != -1) return size;

      size = 0;
      if (!com.google.protobuf.GeneratedMessage.isStringEmpty(name_)) {
      size += com.google.protobuf.GeneratedMessage.computeStringSize(1, name_);
      }
      if (id_ != 0) {
      size += com.google.protobuf.CodedOutputStream
          .computeInt32Size(2, id_);
      }
      {
      int dataSize = 0;
      for (int i = 0; i < emails_.size(); i++) {
          dataSize += computeStringSizeNoTag(emails_.getRaw(i));
      }
      size += dataSize;
      size += 1 * getEmailsList().size();
      }
      size += getUnknownFields().getSerializedSize();
      memoizedSize = size;
      return size;
    }

    @java.lang.Override
    public boolean equals(final java.lang.Object obj) {
      if (obj == this) {
       return true;
      }
      if (!(obj instanceof PersonOuterClass.Person)) {
      return super.equals(obj);
      }
      PersonOuterClass.Person other = (PersonOuterClass.Person) obj;

      if (!getName()
          .equals(other.getName())) return false;
      if (getId()
          != other.getId()) return false;
      if (!getEmailsList()
          .equals(other.getEmailsList())) return false;
      if (!getUnknownFields().equals(other.getUnknownFields())) return false;
      return true;
    }

    @java.lang.Override
    public int hashCode() {
      if (memoizedHashCode != 0) {
      return memoizedHashCode;
      }
      int hash = 41;
      hash = (19 * hash) + getDescriptor().hashCode();
      hash = (37 * hash) + NAME_FIELD_NUMBER;
      hash = (53 * hash) + getName().hashCode();
      hash = (37 * hash) + ID_FIELD_NUMBER;
      hash = (53 * hash) + getId();
      if (getEmailsCount() > 0) {
      hash = (37 * hash) + EMAILS_FIELD_NUMBER;
      hash = (53 * hash) + getEmailsList().hashCode();
      }
      hash = (29 * hash) + getUnknownFields().hashCode();
      memoizedHashCode = hash;
      return hash;
    }

    public static PersonOuterClass.Person parseFrom(
      java.nio.ByteBuffer data)
      throws com.google.protobuf.InvalidProtocolBufferException {
      return PARSER.parseFrom(data);
    }
    public static PersonOuterClass.Person parseFrom(
      java.nio.ByteBuffer data,
      com.google.protobuf.ExtensionRegistryLite extensionRegistry)
      throws com.google.protobuf.InvalidProtocolBufferException {
      return PARSER.parseFrom(data, extensionRegistry);
    }
    public static PersonOuterClass.Person parseFrom(
      com.google.protobuf.ByteString data)
      throws com.google.protobuf.InvalidProtocolBufferException {
      return PARSER.parseFrom(data);
    }
    public static PersonOuterClass.Person parseFrom(
      com.google.protobuf.ByteString data,
      com.google.protobuf.ExtensionRegistryLite extensionRegistry)
      throws com.google.protobuf.InvalidProtocolBufferException {
      return PARSER.parseFrom(data, extensionRegistry);
    }
    public static PersonOuterClass.Person parseFrom(byte[] data)
      throws com.google.protobuf.InvalidProtocolBufferException {
      return PARSER.parseFrom(data);
    }
    public static PersonOuterClass.Person parseFrom(
      byte[] data,
      com.google.protobuf.ExtensionRegistryLite extensionRegistry)
      throws com.google.protobuf.InvalidProtocolBufferException {
      return PARSER.parseFrom(data, extensionRegistry);
    }
    public static PersonOuterClass.Person parseFrom(java.io.InputStream input)
      throws java.io.IOException {
      return com.google.protobuf.GeneratedMessage
          .parseWithIOException(PARSER, input);
    }
    public static PersonOuterClass.Person parseFrom(
      java.io.InputStream input,
      com.google.protobuf.ExtensionRegistryLite extensionRegistry)
      throws java.io.IOException {
      return com.google.protobuf.GeneratedMessage
          .parseWithIOException(PARSER, input, extensionRegistry);
    }

    public static PersonOuterClass.Person parseDelimitedFrom(java.io.InputStream input)
      throws java.io.IOException {
      return com.google.protobuf.GeneratedMessage
          .parseDelimitedWithIOException(PARSER, input);
    }

    public static PersonOuterClass.Person parseDelimitedFrom(
      java.io.InputStream input,
      com.google.protobuf.ExtensionRegistryLite extensionRegistry)
      throws java.io.IOException {
      return com.google.protobuf.GeneratedMessage
          .parseDelimitedWithIOException(PARSER, input, extensionRegistry);
    }
    public static PersonOuterClass.Person parseFrom(
      com.google.protobuf.CodedInputStream input)
      throws java.io.IOException {
      return com.google.protobuf.GeneratedMessage
          .parseWithIOException(PARSER, input);
    }
    public static PersonOuterClass.Person parseFrom(
      com.google.protobuf.CodedInputStream input,
      com.google.protobuf.ExtensionRegistryLite extensionRegistry)
      throws java.io.IOException {
      return com.google.protobuf.GeneratedMessage
          .parseWithIOException(PARSER, input, extensionRegistry);
    }

    @java.lang.Override
    public Builder newBuilderForType() { return newBuilder(); }
    public static Builder newBuilder() {
      return DEFAULT_INSTANCE.toBuilder();
    }
    public static Builder newBuilder(PersonOuterClass.Person prototype) {
      return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype);
    }
    @java.lang.Override
    public Builder toBuilder() {
      return this == DEFAULT_INSTANCE
          ? new Builder() : new Builder().mergeFrom(this);
    }

    @java.lang.Override
    protected Builder newBuilderForType(
      com.google.protobuf.GeneratedMessage.BuilderParent parent) {
      Builder builder = new Builder(parent);
      return builder;
    }
    /**
   * Protobuf type {@code Person}
   */
    public static final class Builder extends
      com.google.protobuf.GeneratedMessage.Builder<Builder> implements
      // @@protoc_insertion_point(builder_implements:Person)
      PersonOuterClass.PersonOrBuilder {
      public static final com.google.protobuf.Descriptors.Descriptor
          getDescriptor() {
      return PersonOuterClass.internal_static_Person_descriptor;
      }

      @java.lang.Override
      protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
          internalGetFieldAccessorTable() {
      return PersonOuterClass.internal_static_Person_fieldAccessorTable
            .ensureFieldAccessorsInitialized(
                PersonOuterClass.Person.class, PersonOuterClass.Person.Builder.class);
      }

      // Construct using PersonOuterClass.Person.newBuilder()
      private Builder() {

      }

      private Builder(
          com.google.protobuf.GeneratedMessage.BuilderParent parent) {
      super(parent);

      }
      @java.lang.Override
      public Builder clear() {
      super.clear();
      bitField0_ = 0;
      name_ = "";
      id_ = 0;
      emails_ =
            com.google.protobuf.LazyStringArrayList.emptyList();
      return this;
      }

      @java.lang.Override
      public com.google.protobuf.Descriptors.Descriptor
          getDescriptorForType() {
      return PersonOuterClass.internal_static_Person_descriptor;
      }

      @java.lang.Override
      public PersonOuterClass.Person getDefaultInstanceForType() {
      return PersonOuterClass.Person.getDefaultInstance();
      }

      @java.lang.Override
      public PersonOuterClass.Person build() {
      PersonOuterClass.Person result = buildPartial();
      if (!result.isInitialized()) {
          throw newUninitializedMessageException(result);
      }
      return result;
      }

      @java.lang.Override
      public PersonOuterClass.Person buildPartial() {
      PersonOuterClass.Person result = new PersonOuterClass.Person(this);
      if (bitField0_ != 0) { buildPartial0(result); }
      onBuilt();
      return result;
      }

      private void buildPartial0(PersonOuterClass.Person result) {
      int from_bitField0_ = bitField0_;
      if (((from_bitField0_ & 0x00000001) != 0)) {
          result.name_ = name_;
      }
      if (((from_bitField0_ & 0x00000002) != 0)) {
          result.id_ = id_;
      }
      if (((from_bitField0_ & 0x00000004) != 0)) {
          emails_.makeImmutable();
          result.emails_ = emails_;
      }
      }

      @java.lang.Override
      public Builder mergeFrom(com.google.protobuf.Message other) {
      if (other instanceof PersonOuterClass.Person) {
          return mergeFrom((PersonOuterClass.Person)other);
      } else {
          super.mergeFrom(other);
          return this;
      }
      }

      public Builder mergeFrom(PersonOuterClass.Person other) {
      if (other == PersonOuterClass.Person.getDefaultInstance()) return this;
      if (!other.getName().isEmpty()) {
          name_ = other.name_;
          bitField0_ |= 0x00000001;
          onChanged();
      }
      if (other.getId() != 0) {
          setId(other.getId());
      }
      if (!other.emails_.isEmpty()) {
          if (emails_.isEmpty()) {
            emails_ = other.emails_;
            bitField0_ |= 0x00000004;
          } else {
            ensureEmailsIsMutable();
            emails_.addAll(other.emails_);
          }
          onChanged();
      }
      this.mergeUnknownFields(other.getUnknownFields());
      onChanged();
      return this;
      }

      @java.lang.Override
      public final boolean isInitialized() {
      return true;
      }

      @java.lang.Override
      public Builder mergeFrom(
          com.google.protobuf.CodedInputStream input,
          com.google.protobuf.ExtensionRegistryLite extensionRegistry)
          throws java.io.IOException {
      if (extensionRegistry == null) {
          throw new java.lang.NullPointerException();
      }
      try {
          boolean done = false;
          while (!done) {
            int tag = input.readTag();
            switch (tag) {
            case 0:
                done = true;
                break;
            case 10: {
                name_ = input.readStringRequireUtf8();
                bitField0_ |= 0x00000001;
                break;
            } // case 10
            case 16: {
                id_ = input.readInt32();
                bitField0_ |= 0x00000002;
                break;
            } // case 16
            case 26: {
                java.lang.String s = input.readStringRequireUtf8();
                ensureEmailsIsMutable();
                emails_.add(s);
                break;
            } // case 26
            default: {
                if (!super.parseUnknownField(input, extensionRegistry, tag)) {
                  done = true; // was an endgroup tag
                }
                break;
            } // default:
            } // switch (tag)
          } // while (!done)
      } catch (com.google.protobuf.InvalidProtocolBufferException e) {
          throw e.unwrapIOException();
      } finally {
          onChanged();
      } // finally
      return this;
      }
      private int bitField0_;

      private java.lang.Object name_ = "";
      /**
       * string name = 1;
       * @return The name.
       */
      public java.lang.String getName() {
      java.lang.Object ref = name_;
      if (!(ref instanceof java.lang.String)) {
          com.google.protobuf.ByteString bs =
            (com.google.protobuf.ByteString) ref;
          java.lang.String s = bs.toStringUtf8();
          name_ = s;
          return s;
      } else {
          return (java.lang.String) ref;
      }
      }
      /**
       * string name = 1;
       * @return The bytes for name.
       */
      public com.google.protobuf.ByteString
          getNameBytes() {
      java.lang.Object ref = name_;
      if (ref instanceof String) {
          com.google.protobuf.ByteString b =
            com.google.protobuf.ByteString.copyFromUtf8(
                  (java.lang.String) ref);
          name_ = b;
          return b;
      } else {
          return (com.google.protobuf.ByteString) ref;
      }
      }
      /**
       * string name = 1;
       * @param value The name to set.
       * @return This builder for chaining.
       */
      public Builder setName(
          java.lang.String value) {
      if (value == null) { throw new NullPointerException(); }
      name_ = value;
      bitField0_ |= 0x00000001;
      onChanged();
      return this;
      }
      /**
       * string name = 1;
       * @return This builder for chaining.
       */
      public Builder clearName() {
      name_ = getDefaultInstance().getName();
      bitField0_ = (bitField0_ & ~0x00000001);
      onChanged();
      return this;
      }
      /**
       * string name = 1;
       * @param value The bytes for name to set.
       * @return This builder for chaining.
       */
      public Builder setNameBytes(
          com.google.protobuf.ByteString value) {
      if (value == null) { throw new NullPointerException(); }
      checkByteStringIsUtf8(value);
      name_ = value;
      bitField0_ |= 0x00000001;
      onChanged();
      return this;
      }

      private int id_ ;
      /**
       * int32 id = 2;
       * @return The id.
       */
      @java.lang.Override
      public int getId() {
      return id_;
      }
      /**
       * int32 id = 2;
       * @param value The id to set.
       * @return This builder for chaining.
       */
      public Builder setId(int value) {

      id_ = value;
      bitField0_ |= 0x00000002;
      onChanged();
      return this;
      }
      /**
       * int32 id = 2;
       * @return This builder for chaining.
       */
      public Builder clearId() {
      bitField0_ = (bitField0_ & ~0x00000002);
      id_ = 0;
      onChanged();
      return this;
      }

      private com.google.protobuf.LazyStringArrayList emails_ =
          com.google.protobuf.LazyStringArrayList.emptyList();
      private void ensureEmailsIsMutable() {
      if (!emails_.isModifiable()) {
          emails_ = new com.google.protobuf.LazyStringArrayList(emails_);
      }
      bitField0_ |= 0x00000004;
      }
      /**
       * repeated string emails = 3;
       * @return A list containing the emails.
       */
      public com.google.protobuf.ProtocolStringList
          getEmailsList() {
      emails_.makeImmutable();
      return emails_;
      }
      /**
       * repeated string emails = 3;
       * @return The count of emails.
       */
      public int getEmailsCount() {
      return emails_.size();
      }
      /**
       * repeated string emails = 3;
       * @param index The index of the element to return.
       * @return The emails at the given index.
       */
      public java.lang.String getEmails(int index) {
      return emails_.get(index);
      }
      /**
       * repeated string emails = 3;
       * @param index The index of the value to return.
       * @return The bytes of the emails at the given index.
       */
      public com.google.protobuf.ByteString
          getEmailsBytes(int index) {
      return emails_.getByteString(index);
      }
      /**
       * repeated string emails = 3;
       * @param index The index to set the value at.
       * @param value The emails to set.
       * @return This builder for chaining.
       */
      public Builder setEmails(
          int index, java.lang.String value) {
      if (value == null) { throw new NullPointerException(); }
      ensureEmailsIsMutable();
      emails_.set(index, value);
      bitField0_ |= 0x00000004;
      onChanged();
      return this;
      }
      /**
       * repeated string emails = 3;
       * @param value The emails to add.
       * @return This builder for chaining.
       */
      public Builder addEmails(
          java.lang.String value) {
      if (value == null) { throw new NullPointerException(); }
      ensureEmailsIsMutable();
      emails_.add(value);
      bitField0_ |= 0x00000004;
      onChanged();
      return this;
      }
      /**
       * repeated string emails = 3;
       * @param values The emails to add.
       * @return This builder for chaining.
       */
      public Builder addAllEmails(
          java.lang.Iterable<java.lang.String> values) {
      ensureEmailsIsMutable();
      com.google.protobuf.AbstractMessageLite.Builder.addAll(
            values, emails_);
      bitField0_ |= 0x00000004;
      onChanged();
      return this;
      }
      /**
       * repeated string emails = 3;
       * @return This builder for chaining.
       */
      public Builder clearEmails() {
      emails_ =
          com.google.protobuf.LazyStringArrayList.emptyList();
      bitField0_ = (bitField0_ & ~0x00000004);;
      onChanged();
      return this;
      }
      /**
       * repeated string emails = 3;
       * @param value The bytes of the emails to add.
       * @return This builder for chaining.
       */
      public Builder addEmailsBytes(
          com.google.protobuf.ByteString value) {
      if (value == null) { throw new NullPointerException(); }
      checkByteStringIsUtf8(value);
      ensureEmailsIsMutable();
      emails_.add(value);
      bitField0_ |= 0x00000004;
      onChanged();
      return this;
      }

      // @@protoc_insertion_point(builder_scope:Person)
    }

    // @@protoc_insertion_point(class_scope:Person)
    private static final PersonOuterClass.Person DEFAULT_INSTANCE;
    static {
      DEFAULT_INSTANCE = new PersonOuterClass.Person();
    }

    public static PersonOuterClass.Person getDefaultInstance() {
      return DEFAULT_INSTANCE;
    }

    private static final com.google.protobuf.Parser<Person>
      PARSER = new com.google.protobuf.AbstractParser<Person>() {
      @java.lang.Override
      public Person parsePartialFrom(
          com.google.protobuf.CodedInputStream input,
          com.google.protobuf.ExtensionRegistryLite extensionRegistry)
          throws com.google.protobuf.InvalidProtocolBufferException {
      Builder builder = newBuilder();
      try {
          builder.mergeFrom(input, extensionRegistry);
      } catch (com.google.protobuf.InvalidProtocolBufferException e) {
          throw e.setUnfinishedMessage(builder.buildPartial());
      } catch (com.google.protobuf.UninitializedMessageException e) {
          throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial());
      } catch (java.io.IOException e) {
          throw new com.google.protobuf.InvalidProtocolBufferException(e)
            .setUnfinishedMessage(builder.buildPartial());
      }
      return builder.buildPartial();
      }
    };

    public static com.google.protobuf.Parser<Person> parser() {
      return PARSER;
    }

    @java.lang.Override
    public com.google.protobuf.Parser<Person> getParserForType() {
      return PARSER;
    }

    @java.lang.Override
    public PersonOuterClass.Person getDefaultInstanceForType() {
      return DEFAULT_INSTANCE;
    }

}

private static final com.google.protobuf.Descriptors.Descriptor
    internal_static_Person_descriptor;
private static final
    com.google.protobuf.GeneratedMessage.FieldAccessorTable
      internal_static_Person_fieldAccessorTable;

public static com.google.protobuf.Descriptors.FileDescriptor
      getDescriptor() {
    return descriptor;
}
private staticcom.google.protobuf.Descriptors.FileDescriptor
      descriptor;
static {
    java.lang.String[] descriptorData = {
      "\n\014person.proto\"2\n\006Person\022\014\n\004name\030\001 \001(\t\022\n" +
      "\n\002id\030\002 \001(\005\022\016\n\006emails\030\003 \003(\tb\006proto3"
    };
    descriptor = com.google.protobuf.Descriptors.FileDescriptor
      .internalBuildGeneratedFileFrom(descriptorData,
      new com.google.protobuf.Descriptors.FileDescriptor[] {
      });
    internal_static_Person_descriptor =
      getDescriptor().getMessageTypes().get(0);
    internal_static_Person_fieldAccessorTable = new
      com.google.protobuf.GeneratedMessage.FieldAccessorTable(
      internal_static_Person_descriptor,
      new java.lang.String[] { "Name", "Id", "Emails", });
    descriptor.resolveAllFeaturesImmutable();
}

// @@protoc_insertion_point(outer_class_scope)
}执行

从上面编译出来的文件中可以找到这行注释// Protobuf Java Version: 4.31.1,表示protobuf对应java依赖的版本。

[*]在pom.xml中引入依赖
<dependency>
<groupId>com.google.protobuf</groupId>
protobuf-java</artifactId>
<version>4.31.1</version>
</dependency>

[*]java测试代码
public static void main(String[] args) throws InvalidProtocolBufferException {
    // 构造对象
    PersonOuterClass.Person person = PersonOuterClass.Person.newBuilder()
    .setName("Alice")
    .setId(123)
    .addEmails("alice@example.com")
    .build();

    // 序列化为字节数组
    byte[] bytes = person.toByteArray();

    // 反序列化
    PersonOuterClass.Person parsedPerson = PersonOuterClass.Person.parseFrom(bytes);
    System.out.println(parsedPerson.getName());
    System.out.println(parsedPerson.getId());
    System.out.println(parsedPerson.getEmails(0));

}

[*]执行结果
Alice
123
alice@example.com性能测试

protobuf和json的性能对比

此处对比protobuf、hutool的json工具类、jackson的性能

[*]引入依赖
<dependency>
<groupId>org.junit.jupiter</groupId>
junit-jupiter-api</artifactId>
<version>5.8.2</version>
</dependency>

<dependency>
<groupId>org.openjdk.jmh</groupId>
jmh-core</artifactId>
<version>1.37</version>
</dependency>

<dependency>
<groupId>org.openjdk.jmh</groupId>
jmh-generator-annprocess</artifactId>
<version>1.37</version>
<scope>provided</scope>
</dependency>


<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
jackson-databind</artifactId>
<version>2.15.2</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
jackson-core</artifactId>
<version>2.15.2</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
jackson-annotations</artifactId>
<version>2.15.2</version>
</dependency>


<dependency>
<groupId>cn.hutool</groupId>
hutool-all</artifactId>
<version>5.8.27</version>
</dependency>

[*]测试的pojo类
public class PersonJson {

    private String name;
    private int id;
    private String[] emails;

    public String getName() {
      return name;
    }

    public void setName(String name) {
      this.name = name;
    }

    public int getId() {
      return id;
    }

    public void setId(int id) {
      this.id = id;
    }

    public String[] getEmails() {
      return emails;
    }

    public void setEmails(String[] emails) {
      this.emails = emails;
    }
}

[*]测试代码
package protobuf;

import cn.hutool.json.JSONUtil;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.openjdk.jmh.annotations.*;

import java.io.IOException;

@Warmup(iterations = 2, time = 1)
@Measurement(iterations = 2, time = 1)
@Fork(2)
@State(Scope.Thread)
public class ProtobufBenchmark {
    private PersonOuterClass.Person person;
    private byte[] serializedData;
    private String jsonStr;

    private PersonJson personJson;

    private ObjectMapper objectMapper = new ObjectMapper();

    @Setup
    public void setup() {
      person = PersonOuterClass.Person.newBuilder()
                .setName("Charlie")
                .setId(789)
                .addEmails("charlie@example.com")
                .build();
      serializedData = person.toByteArray();

      personJson = new PersonJson();
      personJson.setName("Charlie");
      personJson.setId(789);
      personJson.setEmails(new String[]{"charlie@example.com"});

      jsonStr = JSONUtil.toJsonStr(personJson);
    }

    /**
   * 测试protobuf序列化
   *
   * @return
   */
    @Benchmark
    public byte[] testSerialize() {
      return person.toByteArray();
    }

    /**
   * 测试protobuf反序列化
   *
   * @return
   * @throws Exception
   */
    @Benchmark
    public PersonOuterClass.Person testDeserialize() throws Exception {
      return PersonOuterClass.Person.parseFrom(serializedData);
    }

    /**
   * 测试hutool-json序列化
   *
   * @return
   */
    @Benchmark
    public String testJsonSerialize() {
      return JSONUtil.toJsonStr(personJson);
    }

    /**
   * 测试hutool-json反序列化
   *
   * @return
   */
    @Benchmark
    public PersonJson testJsonDeserialize() {
      return JSONUtil.toBean(jsonStr, PersonJson.class);
    }

    /**
   * 测试Jackson序列化
   *
   * @return
   * @throws JsonProcessingException
   */
    @Benchmark
    public String testJacksonSerialize() throws JsonProcessingException {
      return objectMapper.writeValueAsString(personJson);
    }

    /**
   * 测试Jackson反序列化
   *
   * @return
   * @throws Exception
   */
    @Benchmark
    public PersonJson testJacksonDeserialize() throws Exception {
      return objectMapper.readValue(jsonStr, PersonJson.class);
    }

}运行结果

Benchmark                                  ModeCnt         Score         ErrorUnits
ProtobufBenchmark.testSerialize         thrpt    423652174.844 ± 1801935.493ops/s
ProtobufBenchmark.testDeserialize         thrpt    4   7830878.513 ± 2204277.060ops/s
ProtobufBenchmark.testJacksonSerialize    thrpt    4   5737731.097 ±975288.754ops/s
ProtobufBenchmark.testJacksonDeserializethrpt    4   2806124.511 ±396224.766ops/s
ProtobufBenchmark.testJsonSerialize       thrpt    4    256885.571 ±   42109.112ops/s
ProtobufBenchmark.testJsonDeserialize   thrpt    4    289602.156 ±   78181.194ops/s

[*]protobuf序列化性能是jackson的4倍,反序列化性能也将近3倍
[*]hutool的json性能就比较差了,所以实际项目中若要使用json,推荐使用jackson
小结

本文介绍了protobuf从安装到使用的全过程,并提供了相应的代码示例。读者可以通过直接运行代码示例直观的学习到protobuf如何使用。最后测试和对比了protobuf、json序列化和反序列化的性能。

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
页: [1]
查看完整版本: 高效编解码协议之protobuf协议详解