完整教程:【030】Dubbo3从0到1系列之dubbo-serialization模块

四、dubbo-serialization

4.1 模块结构

Dubbo 为了支持多种序列化算法,单独抽象了一层 Serialize 层,在整个 Dubbo 架构中处于最底层,对应的模块是 dubbo-serialization 模块。dubbo-serialization模块结构
在这里插入图片描述

dubbo-serialization-api 模块中定义了 Dubbo 序列化层的核心接口,其中最核心的是 Serialization 这个接口,它是一个扩展接口,被 @SPI 接口修饰,默认扩展实现是 Hessian2Serialization。
在这里插入图片描述

4.2 Serialization

Serialization 接口是 Apache Dubbo 框架中的一个核心 SPI(Service Provider Interface)接口,用于定义序列化策略。它允许框架支持多种不同的序列化实现,并且可以在运行时根据配置动态切换。

package org.apache.dubbo.common.serialize;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.extension.Adaptive;
import org.apache.dubbo.common.extension.ExtensionScope;
import org.apache.dubbo.common.extension.SPI;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
@SPI(scope = ExtensionScope.FRAMEWORK)
public interface Serialization {
byte getContentTypeId();
String getContentType();
@Adaptive
ObjectOutput serialize(URL url, OutputStream output) throws IOException;
@Adaptive
ObjectInput deserialize(URL url, InputStream input) throws IOException;
}

4.2.1 基本信息

  • 包路径: org.apache.dubbo.common.serialize

  • 注解:

    • @SPI(scope = ExtensionScope.FRAMEWORK):标记为 SPI 扩展点,作用域为框架级别方法上的 @Adaptive 注解表示这些方法可以通过适配器模式动态选择具体实现;
  • 核心作用

    • Serialization 接口的主要目的是提供统一的序列化和反序列化操作接口,使得 Dubbo 可以灵活地支持各种序列化协议;

4.2.2 getContentTypeId

获取内容类型标识符

byte getContentTypeId();

此方法返回该序列化方式的唯一标识符(content type id)。需要注意以下几点:

  • 自定义实现应使用不同于 Constants 中任何值的 ID
  • 不应大于 ExchangeCodec.SERIALIZATION_MASK(即 31)
  • 因为 Dubbo 协议在消息头中使用 5 位来记录序列化 ID

4.2.3 getContentType

获取内容类型字符串

String getContentType();

返回序列化的 MIME 类型字符串,例如 “application/hessian2” 或其他自定义类型。

4.2.4 序列化操作

@Adaptive
ObjectOutput serialize(URL url, OutputStream output) throws IOException;

创建并返回一个 ObjectOutput 实例,用于将对象序列化到输出流中:

  • 参数 url 是远程服务的 URL 地址,可用于获取序列化相关配置
  • 参数 output 是底层输出流
  • 返回值是一个实现了 ObjectOutput 接口的对象,负责实际的序列化工作

4.2.5 反序列化操作

@Adaptive
ObjectInput deserialize(URL url, InputStream input) throws IOException;

创建并返回一个 ObjectInput 实例,用于从输入流中读取并反序列化对象:

  • 参数 url 是远程服务的 URL 地址,可用于获取反序列化相关配置
  • 参数 input 是底层输入流
  • 返回值是一个实现了 ObjectInput 接口的对象,负责实际的反序列化工作

4.2.6 使用方式

默认情况下,Dubbo 使用 Hessian2 作为序列化实现。用户可以通过以下方式进行配置:

<dubbo:protocol serialization="hessian2" />

或者通过其他支持的序列化方式如 fastjson、kryo 等。

4.2.7 设计特点

SPI机制:采用 Dubbo 的 SPI 机制,方便扩展新的序列化实现
适配器模式:通过 @Adaptive 注解实现自动适配具体的序列化实现
线程安全:设计上保证了线程安全性
✅ 可插拔性:不同协议和服务可以独立选择合适的序列化方案

4.3 Hessian2Serialization

dubbo默认的序列化方式.以它为例进行说明dubbo对于序列化/反序列化的处理

  • 源码如下所示:
package org.apache.dubbo.common.serialize.hessian2;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.logger.Logger;
import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.common.serialize.ObjectInput;
import org.apache.dubbo.common.serialize.ObjectOutput;
import org.apache.dubbo.common.serialize.Serialization;
import org.apache.dubbo.rpc.model.FrameworkModel;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Optional;
import static org.apache.dubbo.common.serialize.Constants.HESSIAN2_SERIALIZATION_ID;
public class Hessian2Serialization implements Serialization {
private static final Logger logger = LoggerFactory.getLogger(Hessian2Serialization.class);
static {
Class<?> aClass = null;
  try {
  aClass = com.alibaba.com.caucho.hessian.io.Hessian2Output.class;
  } catch (Throwable ignored) {
  }
  if (aClass == null) {
  logger.info(
  "Failed to load com.alibaba.com.caucho.hessian.io.Hessian2Output, hessian2 serialization will be disabled.");
  throw new IllegalStateException("The hessian2 is not in classpath.");
  }
  }
  @Override
  public byte getContentTypeId() {
  return HESSIAN2_SERIALIZATION_ID;
  }
  @Override
  public String getContentType() {
  return "x-application/hessian2";
  }
  @Override
  public ObjectOutput serialize(URL url, OutputStream out) throws IOException {
  Hessian2FactoryManager hessian2FactoryManager = Optional.ofNullable(url)
  .map(URL::getOrDefaultFrameworkModel)
  .orElseGet(FrameworkModel::defaultModel)
  .getBeanFactory()
  .getBean(Hessian2FactoryManager.class);
  return new Hessian2ObjectOutput(out, hessian2FactoryManager);
  }
  @Override
  public ObjectInput deserialize(URL url, InputStream is) throws IOException {
  Hessian2FactoryManager hessian2FactoryManager = Optional.ofNullable(url)
  .map(URL::getOrDefaultFrameworkModel)
  .orElseGet(FrameworkModel::defaultModel)
  .getBeanFactory()
  .getBean(Hessian2FactoryManager.class);
  return new Hessian2ObjectInput(is, hessian2FactoryManager);
  }
  }

4.3.1 基本信息

Hessian2Serialization 是 Apache Dubbo 中对 Hessian2 序列化协议的具体实现类,它是 Dubbo 默认的序列化方式。

基本信息

  • 包路径: org.apache.dubbo.common.serialize.hessian2
  • 实现接口: Serialization
  • 默认启用: 作为 Dubbo 协议的默认序列化实现

4.3.2 静态方法初始化

static {
Class<?> aClass = null;
  try {
  aClass = com.alibaba.com.caucho.hessian.io.Hessian2Output.class;
  } catch (Throwable ignored) {
  }
  if (aClass == null) {
  logger.info(
  "Failed to load com.alibaba.com.caucho.hessian.io.Hessian2Output, hessian2 serialization will be disabled.");
  throw new IllegalStateException("The hessian2 is not in classpath.");
  }
  }
  • 在类加载时检查 Hessian2 相关类是否存在
  • 如果找不到 Hessian2Output 类,则抛出异常禁用 Hessian2 序列化
  • 这确保了只有在类路径中存在 Hessian2 依赖时才能使用该序列化方式

4.3.3 获取信息

  • getContentTypeId()
    • 返回 Hessian2 序列化的唯一标识符
    • 使用 HESSIAN2_SERIALIZATION_ID 常量作为内容类型ID
@Override
public byte getContentTypeId() {
return HESSIAN2_SERIALIZATION_ID;
}

相关常量定义:

public interface Constants {
byte HESSIAN2_SERIALIZATION_ID = 2;
byte JAVA_SERIALIZATION_ID = 3;
byte COMPACTED_JAVA_SERIALIZATION_ID = 4;
byte FASTJSON_SERIALIZATION_ID = 6;
byte NATIVE_JAVA_SERIALIZATION_ID = 7;
byte KRYO_SERIALIZATION_ID = 8;
byte FST_SERIALIZATION_ID = 9;
byte NATIVE_HESSIAN_SERIALIZATION_ID = 10;
byte PROTOSTUFF_SERIALIZATION_ID = 12;
byte AVRO_SERIALIZATION_ID = 11;
byte GSON_SERIALIZATION_ID = 16;
byte JACKSON_SERIALIZATION_ID = 18;
byte PROTOBUF_JSON_SERIALIZATION_ID = 21;
byte PROTOBUF_SERIALIZATION_ID = 22;
byte FASTJSON2_SERIALIZATION_ID = 23;
byte KRYO_SERIALIZATION2_ID = 25;
byte MSGPACK_SERIALIZATION_ID = 27;
byte FURY_SERIALIZATION_ID = 28;
byte CUSTOM_MESSAGE_PACK_ID = 31;
}
  • getContentType()
@Override
public String getContentType() {
return "x-application/hessian2";
}
  • 返回 Hessian2 的 MIME 类型字符串
  • 使用 “x-application/hessian2” 作为内容类型

4.3.4 序列化

@Override
public ObjectOutput serialize(URL url, OutputStream out) throws IOException {
Hessian2FactoryManager hessian2FactoryManager = Optional.ofNullable(url)
.map(URL::getOrDefaultFrameworkModel)
.orElseGet(FrameworkModel::defaultModel)
.getBeanFactory()
.getBean(Hessian2FactoryManager.class);
return new Hessian2ObjectOutput(out, hessian2FactoryManager);
}
  • 创建 Hessian2ObjectOutput 实例用于序列化
  • 通过 URL 获取 FrameworkModel,进而获取 Hessian2FactoryManager
  • 使用工厂管理器和输出流构造 Hessian2ObjectOutput 对象

4.3.5 反序列化

@Override
public ObjectInput deserialize(URL url, InputStream is) throws IOException {
Hessian2FactoryManager hessian2FactoryManager = Optional.ofNullable(url)
.map(URL::getOrDefaultFrameworkModel)
.orElseGet(FrameworkModel::defaultModel)
.getBeanFactory()
.getBean(Hessian2FactoryManager.class);
return new Hessian2ObjectInput(is, hessian2FactoryManager);
}
  • 创建 Hessian2ObjectInput 实例用于反序列化
  • 同样通过 URL 获取 Hessian2FactoryManager
  • 使用工厂管理器和输入流构造 Hessian2ObjectInput 对象

4.3.6 关键组件

✅ Hessian2FactoryManager

  • 管理 Hessian2 序列化所需的工厂对象
  • 通过 FrameworkModel 的 Bean 工厂获取实例
  • 提供序列化和反序列化过程中需要的辅助工具

Hessian2ObjectOutput/Hessian2ObjectInput

  • 分别实现 ObjectOutput 和 ObjectInput 接口
  • 负责具体的序列化和反序列化操作
  • 利用 Hessian2 库完成对象与字节流之间的转换

在这里插入图片描述

在 DataOutput 接口中定义了序列化 Java 中各种数据类型的相应方法,如下图所示,其中有序列化 boolean、short、int、long 等基础类型的方法,也有序列化 String、byte[] 的方法。

image-20251102212048257

ObjectOutput 接口继承了 DataOutput 接口,并在其基础之上,添加了序列化对象的功能,具体定义如下图所示,其中的 writeThrowable()、writeEvent() 和 writeAttachments() 方法都是调用 writeObject() 方法实现的。

在这里插入图片描述

在dubbo可以通过以下方式指定序列化方式:

<dubbo:protocol serialization="hessian2" />

由于 Hessian2 是默认序列化方式,即使不显式配置也会被使用

4.3.7 设计特点

依赖检查: 在类加载阶段就验证 Hessian2 依赖的存在性
框架集成: 与 Dubbo 的 FrameworkModel 紧密集成
工厂模式: 使用 Hessian2FactoryManager 管理序列化工厂
SPI 兼容: 实现 Serialization 接口,符合 Dubbo SPI 机制

posted @ 2025-12-09 17:41  clnchanpin  阅读(0)  评论(0)    收藏  举报