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=文件夹路径
  • 编辑环境变量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>
<artifactId>protobuf-maven-plugin</artifactId>
<version>0.6.1</version>
<executions>
<execution>
<goals>
<goal>compile</goal>
</goals>
</execution>
</executions>
<configuration>
<!-- 从 Path 中查找 -->
<protocExecutable>protoc</protocExecutable>
<!-- 或直接指定路径 -->
<!--<protocExecutable>xxx\bin\protoc.exe</protocExecutable>-->
</configuration>
</plugin>
</plugins>
</build>
  • 插件默认读取文件夹/src/main/proto下的proto文件去编译
  • 在文件夹target/generated-sources/protobuf/java下会生成对应pojo的protobuf操作类

注意:

  1. 若执行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
  2. 若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 { /**
* <code>string name = 1;</code>
* @return The name.
*/
java.lang.String getName();
/**
* <code>string name = 1;</code>
* @return The bytes for name.
*/
com.google.protobuf.ByteString
getNameBytes(); /**
* <code>int32 id = 2;</code>
* @return The id.
*/
int getId(); /**
* <code>repeated string emails = 3;</code>
* @return A list containing the emails.
*/
java.util.List<java.lang.String>
getEmailsList();
/**
* <code>repeated string emails = 3;</code>
* @return The count of emails.
*/
int getEmailsCount();
/**
* <code>repeated string emails = 3;</code>
* @param index The index of the element to return.
* @return The emails at the given index.
*/
java.lang.String getEmails(int index);
/**
* <code>repeated string emails = 3;</code>
* @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_ = "";
/**
* <code>string name = 1;</code>
* @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;
}
}
/**
* <code>string name = 1;</code>
* @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;
/**
* <code>int32 id = 2;</code>
* @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();
/**
* <code>repeated string emails = 3;</code>
* @return A list containing the emails.
*/
public com.google.protobuf.ProtocolStringList
getEmailsList() {
return emails_;
}
/**
* <code>repeated string emails = 3;</code>
* @return The count of emails.
*/
public int getEmailsCount() {
return emails_.size();
}
/**
* <code>repeated string emails = 3;</code>
* @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);
}
/**
* <code>repeated string emails = 3;</code>
* @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_ = "";
/**
* <code>string name = 1;</code>
* @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;
}
}
/**
* <code>string name = 1;</code>
* @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;
}
}
/**
* <code>string name = 1;</code>
* @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;
}
/**
* <code>string name = 1;</code>
* @return This builder for chaining.
*/
public Builder clearName() {
name_ = getDefaultInstance().getName();
bitField0_ = (bitField0_ & ~0x00000001);
onChanged();
return this;
}
/**
* <code>string name = 1;</code>
* @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_ ;
/**
* <code>int32 id = 2;</code>
* @return The id.
*/
@java.lang.Override
public int getId() {
return id_;
}
/**
* <code>int32 id = 2;</code>
* @param value The id to set.
* @return This builder for chaining.
*/
public Builder setId(int value) { id_ = value;
bitField0_ |= 0x00000002;
onChanged();
return this;
}
/**
* <code>int32 id = 2;</code>
* @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;
}
/**
* <code>repeated string emails = 3;</code>
* @return A list containing the emails.
*/
public com.google.protobuf.ProtocolStringList
getEmailsList() {
emails_.makeImmutable();
return emails_;
}
/**
* <code>repeated string emails = 3;</code>
* @return The count of emails.
*/
public int getEmailsCount() {
return emails_.size();
}
/**
* <code>repeated string emails = 3;</code>
* @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);
}
/**
* <code>repeated string emails = 3;</code>
* @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);
}
/**
* <code>repeated string emails = 3;</code>
* @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;
}
/**
* <code>repeated string emails = 3;</code>
* @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;
}
/**
* <code>repeated string emails = 3;</code>
* @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;
}
/**
* <code>repeated string emails = 3;</code>
* @return This builder for chaining.
*/
public Builder clearEmails() {
emails_ =
com.google.protobuf.LazyStringArrayList.emptyList();
bitField0_ = (bitField0_ & ~0x00000004);;
onChanged();
return this;
}
/**
* <code>repeated string emails = 3;</code>
* @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 static com.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中引入依赖
<!-- Protobuf Java -->
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>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的性能

  • 引入依赖
<!-- JUnit 5 -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.8.2</version>
</dependency>
<!-- jmh性能测试 -->
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-core</artifactId>
<version>1.37</version>
</dependency>
<!-- 编译时处理JMH的注解,若不加,编译出来的benchmark注解未被解析,运行时会报错 -->
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-generator-annprocess</artifactId>
<version>1.37</version>
<scope>provided</scope>
</dependency> <!-- jackson 依赖 -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.15.2</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.15.2</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.15.2</version>
</dependency> <!-- hutool 依赖 -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>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                                  Mode  Cnt         Score         Error  Units
ProtobufBenchmark.testSerialize thrpt 4 23652174.844 ± 1801935.493 ops/s
ProtobufBenchmark.testDeserialize thrpt 4 7830878.513 ± 2204277.060 ops/s
ProtobufBenchmark.testJacksonSerialize thrpt 4 5737731.097 ± 975288.754 ops/s
ProtobufBenchmark.testJacksonDeserialize thrpt 4 2806124.511 ± 396224.766 ops/s
ProtobufBenchmark.testJsonSerialize thrpt 4 256885.571 ± 42109.112 ops/s
ProtobufBenchmark.testJsonDeserialize thrpt 4 289602.156 ± 78181.194 ops/s
  • protobuf序列化性能是jackson的4倍,反序列化性能也将近3倍
  • hutool的json性能就比较差了,所以实际项目中若要使用json,推荐使用jackson

小结

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

高效编解码协议之protobuf协议详解的更多相关文章

  1. 第8章 应用协议 图解TCP/IP 详解

    第8章 应用协议 图解TCP/IP 详解 8.1 应用层协议概要 应用层协议的定义 TCP和IP等下层协议是不依赖上层应用类型.实用性非常广的协议.而应用协议则是为了实现某种应用而设计和创造的协议. ...

  2. TCP协议粘包问题详解

    TCP协议粘包问题详解 前言 在本章节中,我们将探讨TCP协议基于流式传输的最大一个问题,即粘包问题.本章主要介绍TCP粘包的原理与其三种解决粘包的方案.并且还会介绍为什么UDP协议不会产生粘包. 基 ...

  3. HTTP协议 (六) 状态码详解

    HTTP协议 (六) 状态码详解 HTTP状态码,我都是现查现用. 我以前记得几个常用的状态码,比如200,302,304,404, 503. 一般来说我也只需要了解这些常用的状态码就可以了.  如果 ...

  4. SSL协议之数据加密过程详解

    前言 总括: 原文博客地址:SSL协议之数据加密过程详解 知乎专栏&&简书专题:前端进击者(知乎)&&前端进击者(简书) 博主博客地址:Damonare的个人博客 生活 ...

  5. 网络编程之TCP/IP各层详解

    网络编程之TCP/IP各层详解 我们将应用层,表示层,会话层并作应用层,从TCP/IP五层协议的角度来阐述每层的由来与功能,搞清楚了每层的主要协议,就理解了整个物联网通信的原理. 首先,用户感知到的只 ...

  6. Android编程之LayoutInflater的inflate方法详解

    LayoutInflater的inflate方法,在fragment的onCreateView方法中经常用到: public View onCreateView(LayoutInflater infl ...

  7. linux网络编程之shutdown() 与 close()函数详解

    linux网络编程之shutdown() 与 close()函数详解 参考TCPIP网络编程和UNP: shutdown函数不能关闭套接字,只能关闭输入和输出流,然后发送EOF,假设套接字为A,那么这 ...

  8. HTTP协议缓存策略深入详解之ETAG妙用

    Etag是什么: Etag 是URL的Entity Tag,用于标示URL对象是否改变,区分不同语言和Session等等.具体内部含义是使服务器控制的,就像Cookie那样. HTTP协议规格说明定义 ...

  9. 安全超文本传输协议(HTTPS)详解

    一.概念与摘要 HTTPS (Secure Hypertext Transfer Protocol)安全超文本传输协议,是一个安全通信通道,它基于HTTP开发用于在客户计算机和服务器之间交换信息.它使 ...

  10. Netty学习(七)-Netty编解码技术以及ProtoBuf和Thrift的介绍

    在前几节我们学习过处理粘包和拆包的问题,用到了Netty提供的几个解码器对不同情况的问题进行处理.功能很是强大.我们有没有去想这么强大的功能是如何实现的呢?背后又用到了什么技术?这一节我们就来处理这个 ...

随机推荐

  1. JavaScript中通过闭包来实现私有变量的一种方法

    'use strict'; const SecretHolder = (function () { const secrets = new WeakMap(); return class { cons ...

  2. Qt图像处理技术五:图像的翻转(横向,竖向)

    Qt图像处理技术五:图像的翻转(横向,竖向) 效果图 竖直翻转(两种方法): QImage Vertical(const QImage &origin) { QImage newImage(Q ...

  3. 4 MyBatis动态SQL之trim元素|转

    摘要:trim标签是一个格式化的标签,可以完成set或者where标签的功能. 1 MyBatis动态SQL之if 语句 2 MyBatis动态sql之where标签|转 3 MyBatis动态SQL ...

  4. CF1992E Novice's Mistake

    CF1992E Novice's Mistake 同步于个人博客. Problem Noobish_Monk 有 \(n\in [1,100]\) 个朋友.每个朋友都给了他 \(a\in [1,100 ...

  5. GoWeb服务器搭建

    GoWeb服务器的创建 1.Web工作原理 2.GoWeb服务器的创建 Go提供了一系列用于创建Web服务器的标准库,而且通过Go创建一个服务器的步骤非常简单,只要通过net/http包调用Liste ...

  6. Python字符串进化史:从青涩到成熟的蜕变

    Python字符串进化史:从青涩到成熟的蜕变 Python 2.x 的字符串世界 在 Python 2.x 的时代,字符串处理已经是编程中的基础操作,但与现在相比,有着不少差异.在 Python 2. ...

  7. Git使用随记

    前言 记录Git软件使用相关的流程.命令. 注:这不是一份专业的教程. Git是什么? Git 是一个用于管理源代码的分布式版本控制系统. 版本控制系统会在您修改文件时记录并保存更改,使用户可以随时恢 ...

  8. 雷池WAF离线安装搭建全流程指南(2025年最新版)

    一.环境要求与准备工作 系统要求 ● 操作系统:Debian12+(推荐大版本一致,如内网使用debian12,在线主机也需debian系列) ● CPU架构:x86_64,需支持SSSE3指令集(可 ...

  9. Function AI 工作流发布:以 AI 重塑企业流程自动化

    AI 工作流如何重塑企业自动化流程 在 AI 技术飞速发展的今天,企业的流程自动化方式也正在发生深刻变革.过去,流程自动化往往依赖于人工配置和固定规则,难以适应复杂.多变的业务场景.而如今, 随着 L ...

  10. tensor_scatter_add算子异同点

    技术背景 在MindSpore的ops下实现了一个tensor_scatter_add算子.这个算子的作用为,例如给定一个shape为(1,2,3,4)的原始tensor,因为这个tensor有4个维 ...