← 中文资源

简体中文版本

Protocol Buffers

Protocol Buffers 是语言中立的模式与二进制序列化格式,提供紧凑、向前兼容的结构化消息。

阅读英文原文

概念定义

Protocol Buffers(protobuf)是模式先行的序列化系统:消息在 .proto 文件中用带编号的字段定义,编译器为其生成多种语言的代码。在线路上它是紧凑的二进制格式,以字段编号而非名称索引,因此负载小、解析快。带来兼容性的是字段编号而非名称:未知字段会被保留,新的可选字段可在不破坏旧读取方的前提下添加。

为什么重要

JSON 可读但在规模下冗长且解析慢,且不携带模式。Protobuf 提供更小的消息、更快的解析,以及能在编译期发现错误的生成类型。其字段编号方案从设计上提供兼容性:生产者可以添加旧消费者会忽略的字段,且随着模式增长,旧数据仍可读取。这使它很适合持续演进的高吞吐服务与流式接口。

工程实践

把字段编号视为永久:绝不复用已退役的编号,代之以保留编号而非删除,因为复用的标签会把旧数据重新解释为新类型。字段默认设为可选,用添加而非删除,并以向后兼容的步骤演进模式。把 protobuf 与模式注册表或带版本的契约配合,使每条被存储或流式传输的消息仍可解码;并记住解释字节需要模式——把它与数据一同保存。

代码示例

import com.fasterxml.jackson.annotation.*;
import com.fasterxml.jackson.databind.*;
import java.util.List;
import java.util.Map;

public class ObjectSerialization {

    @JsonIgnoreProperties(ignoreUnknown = true)
    static class Configuration {
        @JsonProperty("app_name")
        private String appName;

        @JsonProperty("max_connections")
        private int maxConnections;

        @JsonProperty("features")
        private List<String> features;

        @JsonCreator
        public Configuration(
            @JsonProperty("app_name") String appName,
            @JsonProperty("max_connections") int maxConnections,
            @JsonProperty("features") List<String> features
        ) {
            this.appName = appName;
            this.maxConnections = maxConnections;
            this.features = features;
        }

        @Override
        public String toString() {
            return appName + " (max=" + maxConnections + ", features=" + features + ")";
        }
    }

    public static void main(String[] args) throws Exception {
        ObjectMapper mapper = new ObjectMapper();
        mapper.enable(SerializationFeature.INDENT_OUTPUT);

        String json = """
            {
              "app_name": "MyApp",
              "max_connections": 100,
              "features": ["auth", "logging", "cache"]
            }
            """;

        Configuration config = mapper.readValue(json, Configuration.class);
        System.out.println("Deserialized: " + config);

        String output = mapper.writeValueAsString(config);
        System.out.println("Serialized: " + output);
    }
}