java序列化本质是将对象转为byte[],以便网络传输或持久化;rpc中客户端序列化参数为字节数组,服务端反序列化还原对象执行方法,核心依赖serialize()方法及统一协议帧封装。

Java 中序列化将对象转为字节数组,本质是把内存中的对象结构“翻译”成一串可传输、可还原的二进制数据。在 RPC 框架底层通信中,这一步是关键桥梁:客户端把调用参数序列化成 byte[],通过网络(如 Netty 或 Socket)发出去;服务端收到 byte[] 后反序列化还原成原始对象,再执行方法。
序列化怎么生成 byte 数组?
核心就是调用序列化器的 serialize() 方法,输入对象,输出 byte[]。不同实现方式路径略有差异,但目标一致:
-
JDK 原生序列化
要求类实现Serializable接口,用ObjectOutputStream写入ByteArrayOutputStream:ByteArrayOutputStream baos = new ByteArrayOutputStream(); try (ObjectOutputStream oos = new ObjectOutputStream(baos)) { oos.writeObject(user); // user 是 Serializable 对象 } byte[] bytes = baos.toByteArray(); -
Hessian2(Dubbo 默认)
更紧凑、更快,无需实现接口:Hessian2Output out = new Hessian2Output(new ByteArrayOutputStream()); out.writeObject(user); byte[] bytes = out.getBuffer().toByteArray();
-
Protobuf(gRPC 默认)
需提前定义.proto文件并生成 Java 类,调用内置toByteArray():UserProto.User user = UserProto.User.newBuilder() .setId(1001) .setName("Alice") .build(); byte[] bytes = user.toByteArray(); // 直接获得 byte[] -
JSON(如 Jackson)
适合调试或 HTTP 场景,体积大、性能弱,但可读性强:byte[] bytes = objectMapper.writeValueAsBytes(user);
为什么必须是 byte[]?RPC 通信怎么用它?
网络协议(TCP/HTTP)只认字节流,不认 Java 对象。RPC 框架底层依赖 byte[] 实现:
- 封装成统一消息格式(比如加魔数、长度、序列化类型 ID、请求 ID 等头信息)
- 交给 Netty 的
ByteBuf或原生SocketOutputStream发送 - 接收方按协议先读头,再根据长度截取 payload 字节,最后按类型 ID 选择反序列化器还原对象
例如一个简化协议帧可能长这样:
[魔数 4B][总长 4B][序列化类型 1B][请求ID 8B][body: byte[]]
其中 body 就是你序列化出来的 byte[]。
实际写 RPC 框架时怎么设计序列化层?
建议抽象出统一接口,方便切换实现:
public interface Serializer {
<t> byte[] serialize(T obj);
<t> T deserialize(byte[] bytes, Class<t> clazz);
}</t></t></t>
然后注入具体实现:
JdkSerializerHessianSerializerProtobufSerializerJsonSerializer
再配合 SPI 或配置项动态加载,比如 Dubbo 支持 serialization=hessian2 或 serialization=protobuf。
注意:跨语言 RPC(如 gRPC)必须用语言无关的序列化(Protobuf/Thrift),而纯 Java 内部调用可用 Hessian 或 Kryo 提升性能。
不复杂但容易忽略。真正上线时,序列化器选型要兼顾性能、兼容性、可维护性和跨语言需求,不能只图写得快。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











