4-Dubbo Extension 扩展机制源码解析.md

作者: vnjohn / 发表于 2025-05-18 / 专栏: Dubbo 3.3

Dubbo3, 源码

4.1 回顾扩展场景

在初始化应用模型对象时,了解到有几个地方使用扩展机制来创建对象,这一章来具体介绍扩展对象的加载过程,以下是上一章具体有用到的扩展机制

// 扩展访问器
this.extensionDirector = new ExtensionDirector(parent != null ? parent.getExtensionDirector() : null, scope, this);
// 使用扩展机制获取 TypeBuilder
Set<TypeBuilder> tbs = model.getExtensionLoader(TypeBuilder.class).getSupportedExtensionInstances();
// 获取域模型初始化器
ExtensionLoader<ScopeModelInitializer> initializerExtensionLoader = this.getExtensionLoader(ScopeModelInitializer.class);
Set<ScopeModelInitializer> initializers = initializerExtensionLoader.getSupportedExtensionInstances();

// 获取应用模型初始化器
ExtensionLoader<ApplicationInitListener> extensionLoader = this.getExtensionLoader(ApplicationInitListener.class);
Set<String> listenerNames = extensionLoader.getSupportedExtensions();
// 应用模型获取应用扩展器对象
Set<ApplicationExt> exts = this.getExtensionLoader(ApplicationExt.class).getSupportedExtensionInstances();

// 模块模型获取模块扩展器对象
Set<ModuleExt> exts = this.getExtensionLoader(ModuleExt.class).getSupportedExtensionInstances();
// OrderedPropertiesConfiguration 获取有序配置提供器对象
ExtensionLoader<OrderedPropertiesProvider> propertiesProviderExtensionLoader = moduleModel.getExtensionLoader(OrderedPropertiesProvider.class);

4.2 为什么要用到扩展机制?

一个好的程序要遵循一定的设计规范,比如设计模式中的开闭原则,英文全称是 Open Closed Principle,简写为 OCP,对扩展开放、对修改关闭

扩展开放: 指的是系统中的模块、类、方法对它们的提供者(开发者)应该是开放的,提供者可以对系统进行扩展(新增)新的功能

修改关闭: 指的是系统中的模块、类、方法对它们的使用者(调用者)应该是关闭的,使用者在使用这些功能时,不会因为提供方新增了功能而导致使用者也进行相应修改

摘自于官网来介绍 Dubbo 基础特性,如下:

Apache Dubbo 是一款微服务开发框架,它提供了 RPC通信微服务治理 两大关键能力。这意味着,使用 Dubbo 开发的微服务,将具备相互之间的远程发现与通信能力, 同时利用 Dubbo 提供的丰富服务治理能力,可以实现诸如服务发现、负载均衡、流量调度等服务治理诉求。同时 Dubbo 是高度可扩展的,用户几乎可以在任意功能点去定制自己的实现,以改变框架的默认行为来满足自己的业务需求。 Dubbo3 基于 Dubbo2 演进而来,在保持原有核心功能特性的同时, Dubbo3 在易用性、超大规模微服务实践、云原生基础设施适配、安全设计等几大方向上进行了全面升级。 以下文档都将基于 Dubbo3 展开。

修改关闭的地方: 对于 Apache Dubbo 来说,不变的是 RPC 调用过程,微服务治理这些抽象的概念,可以用摘自官网的图表示:

image-20250518011554291

4.3 Dubbo 调用链路

先来看官网的调用链路架构设计图

image-20250518011554291

图例说明:

  • 图中左边淡蓝背景的为服务消费方使用的接口,右边淡绿色背景的为服务提供方使用的接口,位于中轴线上的为双方都使用的接口
  • 图中从上至下分为十层,各层均为单向依赖,右边的黑色箭头代表层之间的依赖关系,每一层都可以剥离上层被复用,其中 Service、Config 层为 API,其他各层均为 SPI
  • 图中绿色小块的为扩展接口,蓝色小块为实现类,图中只显示用于关联各层的实现类
  • 图中蓝色虚线为初始化过程,即启动时组装链,红色实线为方法调用过程,即运行时调用链,紫色三角箭头为继承,可以把子类看作父类的同一个节点,线上的文字为调用的方法

各个模块层说明如下:

1、config 配置层: 对外配置接口,以 ServiceConfig、ReferenceConfig 为中心,可以直接初始化配置类,也可以通过 Spring 解析配置生成配置类

2、proxy 服务代理层: 服务接口透明代理,生成服务的客户端 Stub 和服务器端 Skeleton,以 ServiceProxy 为中心,扩展接口为 ProxyFactory

3、Registry 注册中心层: 封装服务地址的注册与发现,以服务 URL 为中心,扩展接口为 RegistryFactory、Registry、RegistryService

4、cluster 路由层: 封装多个提供者的路由及负载均衡,并桥接注册中心,以 Invoker 为中心,扩展接口为 Cluster、Directory、Router、LoadBalance

5、monitor 监控层: RPC 调用次数和调用时间监控,以 Statistics 为中心,扩展接口为 MonitorFactory、Monitor、MonitorService

6、protocol 远程调用层: 封装请求响应模式,同步转异步,以 Request、Response 为中心,扩展接口为 Exchanger、ExchangeChannel、ExchangeClient、ExchangeServer

7、transport 网络传输层: 抽象 Mina、Netty 为统一接口,以 Message 为中心,扩展接口为 Channel、Transporter、Client、Server、Codec

8、serialize 数据序列化层: 可复用的一些工具,扩展接口为 Serialization、ObjectInput、ObjectOutput、ThreadPool

4.4 Dubbo 扩展部分

查看源码 dubbo-common 模块下 org.apache.dubbo.common.extension 包下的相关实现进行初步认识,如下图:

image-20250518233734093

先简单看下类结构图,再对每个类进行相关的解释

image-20250518233734093

1、ExtensionAccessor: 扩展的统一访问器

2、ExtensionDirector

ExtensionDirector 是一个作用域扩展加载程序管理器

ExtensionDirector 支持多个级别,子级可以继承父级的扩展实例,查找、创建扩展实例的方法类似于 Java classloader

3、ExtensionScope: 扩展 SPI 域,目前有 FRAMEWORK、APPLICATION、MODULE、SELF

FRAMEWORK:扩展实例在框架内使用,与所有应用程序和模块共享,框架范围 SPI 扩展只能获取 FrameworkModel,无法获取 ApplicationModel 和 ModuleModel。一些 SPI 需要在框架内的应用程序之间共享数据,无状态 SPI 在框架内是安全共享的

APPLICATION:扩展实例在一个应用程序中使用,与应用程序的所有模块共享,不同的应用程序创建不同的扩展实例。应用范围 SPI 扩展可以获取 FrameworkModel、ApplicationModel,无法获取 ModuleModel。在框架内隔离不同应用程序中的扩展数据,应用程序内部的所有模块之间共享扩展数据

MODULE:扩展实例在一个模块中使用,不同的模块创建不同的扩展实例,模块范围 SPI 扩展可以获得 FrameworkModel、ApplicationModel、ModuleModel。隔离应用程序内部不同模块的扩展数据

SELF:自给自足,为每个作用域创建一个实例,用于特殊的 SPI 扩展,如 ExtensionInjector

4、ExtensionLoader: ApplicationModel、DubboBootstrap 类被设计为单例或静态。因此它们返回的实例属于 process 或 class loader 范围。若想在一个进程中支持多个 Dubbo 服务器,可能需要重构这三个类

加载 Dubbo 扩展、自动注入依赖项扩展、包装器中的自动包装扩展、默认扩展自适应实例、JDK 自带 SPI、@SPI 服务扩展接口、@Adaptive 自适应扩展点注解、@Active 自动激活扩展点注解

5、ExtensionPostProcessor: 在扩展初始化之前或之后调用的处理器

6、LoadingStrategy: 扩展加载策略,目前有 3 个扩展加载策略,分别从不同文件目录加载扩展

7、DubboInternalLoadingStrategy: Dubbo 内置的扩展加载策略,加载文件目录:META-INF/dubbo/internal/ 扩展

8、DubboLoadingStrategy: Dubbo 普通的扩展加载策略,加载文件目录:META-INF/dubbo/ 扩展

9、ServiceLoadingStrategy: JAVA SPI 加载策略,加载文件目录:META-INF/services/ 扩展

10、Wrapper 注解

11、SPI 注解

12、ExtensionInjector 接口: 为 SPI 扩展提供资源的注入器

13、ExtensionAccessorAsware: SPI 扩展可以实现这个感知接口,以获得适当的 ExtensionAccessor 实例

14、DisableInject 注解

15、AdaptiveClassCodeGenerator: 自适应类的代码生成器

16、Adaptive 注解: 为 ExtensionLoader 注入依赖扩展实例提供有用信息

17、Activate 注解: 该注解对于适应给定条件自动激活某些扩展非常有用,例如 @Activate 可用于在有多个实现时加载某些筛选器扩展,group 指定组条件。框架 SPI 定义了有效的组值,value() 指定 URL 条件中的参数键。SPI 提供程序可以调用 ExtensionLoader#getActiveExtension 方法查找具有给定条件的所有已激活扩展

18、ActivateComparator

19、MultiInstanceActivateComparator

20、WrapperComparator

21、AdaptiveExtensionInjector

22、SpiExtensionInjector

4.5 扩展加载调用过程

以上都是介绍扩展相关的概念,下面通过代码举例来说明扩展的调用过程

4.5.1 扩展调用代码示例

例如 FrameworkModel 对象的初始化 initialize 方法中有如下代码调用:

TypeDefinitionBuilder.initBuilders(this);

TypeDefinitionBuilder 中初始化类型构建器代码如下:

public static void initBuilders(FrameworkModel model) {
  Set<TypeBuilder> tbs = model.getExtensionLoader(TypeBuilder.class).getSupportedExtensionInstances();
  BUILDERS = new ArrayList<>(tbs);
}

4.5.2 Dubbo 分层模型获取扩展加载器对象

扩展调用时对于扩展加载器对象的获取代码如下所示:

model.getExtensionLoader(TypeBuilder.class)

getExtensionLoader 方法来源于 FrameworkModel 类的父类 ScopeModel 实现的接口 ExtensionAccessor

该接口调用 getExtensionLoader 默认方法如下代码:

default <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) {
  return getExtensionDirector().getExtensionLoader(type);
}

获取扩展加载器之前需要先获取扩展访问器,梳理链路如下:

模型对象(FrameworkModel) —> 扩展访问器(ExtensionAccessor) —> 作用域扩展加载程序管理器(ExtensionDirector)

1、getExtensionDirector 方法来源于 FrameworkModel 抽象父类 ScopeModel#getExtensionDirector,返回的类是 ExtensionDirector,其由来是在 ScopeModel#initialize 方法中进行创建的,具体代码如下所示:

this.extensionDirector = new ExtensionDirector(parent != null ? parent.getExtensionDirector() : null, scope, this);

2、getExtensionLoader 方法其实是通过创建好的 ExtensionDirector 扩展访问器进行调用的

在详细介绍 getExtensionLoader 方法调用过程时,先来看下示例扩展类 TypeBuilder 源码

@SPI(scope = ExtensionScope.FRAMEWORK)
public interface TypeBuilder extends Prioritized {

    /**
     * Whether the build accept the class passed in.
     */
    boolean accept(Class<?> clazz);

    /**
     * Build type definition with the type or class.
     */
    TypeDefinition build(Type type, Class<?> clazz, Map<String, TypeDefinition> typeCache);
}

ExtensionDirector 类型中获取扩展加载器的代码,其实就类似于 JVM 类加载器访问加载类的情况,但是该顺序有所不同,Dubbo 扩展加载器遵循以下顺序:

1、先从缓存中查询扩展加载器

2、若前面没找到则查询扩展类型的 scope 所属域,若是 SELF 当前域扩展则直接创建扩展加载器

3、若前面没找到就从父扩展访问器中查询,查询这个扩展是否属于父扩展域

4、前面都没有找到就尝试创建

public <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) {
  // 若扩展加载器已经被销毁则抛出异常
  checkDestroyed();
  // eg.使用 TypeBuilder 对象创建扩展加载器对象
  if (type == null) {
    throw new IllegalArgumentException("Extension type == null");
  }
  // 扩展类型不为接口也要抛出异常,TypeBuilder 类型是一个接口
  if (!type.isInterface()) {
    throw new IllegalArgumentException("Extension type (" + type + ") is not an interface!");
  }
  // 若扩展加载器没有被标注为 SPI 则抛出异常
  if (!withExtensionAnnotation(type)) {
    throw new IllegalArgumentException("Extension type (" + type
                                       + ") is not an extension, because it is NOT annotated with @" + SPI.class.getSimpleName() + "!");
  }

  // 1. find in local cache
  // 被加载的扩展类型对应的扩展加载器会放到 extensionLoadersMap 集合中方便缓存
  ExtensionLoader<T> loader = (ExtensionLoader<T>) extensionLoadersMap.get(type);
  // 查询扩展所属域,这个类型的扩展域是框架级别的 ExtensionScope.FRAMEWORK
  ExtensionScope scope = extensionScopeMap.get(type);
  if (scope == null) {
    SPI annotation = type.getAnnotation(SPI.class);
    scope = annotation.scope();
    extensionScopeMap.put(type, scope);
  }
  // 首次访问的时候当前类型的扩展加载器类型肯定是空的,会走如下两个逻辑中的其中一个进行创建扩展加载器
  // 若扩展域为 SELF 自给自足,为每个作用域创建一个实例,用于特殊 SPI 扩展,如{@link ExtensionInjector}
  if (loader == null && scope == ExtensionScope.SELF) {
    // create an instance in self scope
    loader = createExtensionLoader0(type);
  }

  // 2. find in parent
  // 从父扩展加载器中查询当前扩展加载器是否存在
  // TypeBuilder 作为 FRAMEWORK 框架域 -> parent 是空的先不考虑
  if (loader == null) {
    if (this.parent != null) {
      loader = this.parent.getExtensionLoader(type);
    }
  }

  // 3. create it
  // 这个是我们本次会走的逻辑,大部分是会走这个逻辑来创建扩展加载器对象的
  if (loader == null) {
    loader = createExtensionLoader(type);
  }

  return loader;
}

源码中出现的 withExtensionAnnotation 方法判断其是否存在 SPI 注解,源码如下:

private static boolean withExtensionAnnotation(Class<?> type) {
  return type.isAnnotationPresent(SPI.class);
}

ExtensionDirector#createExtensionLoader 方法,源码如下:

private <T> ExtensionLoader<T> createExtensionLoader(Class<T> type) {
  ExtensionLoader<T> loader = null;
  // 匹配当前域是否匹配
  if (isScopeMatched(type)) {
    // if scope is matched, just create it
    loader = createExtensionLoader0(type);
  }
  return loader;
}

ExtensionDirector#createExtensionLoader0 方法,源码如下:

private <T> ExtensionLoader<T> createExtensionLoader0(Class<T> type) {
  // 检查当前扩展访问器是否被销毁
  checkDestroyed();
  ExtensionLoader<T> loader;
  // 为当前扩展类型创建一个扩展访问器并缓存到当前成员变量 extensionLoadersMap 中
  extensionLoadersMap.putIfAbsent(type, new ExtensionLoader<T>(type, this, scopeModel));
  loader = (ExtensionLoader<T>) extensionLoadersMap.get(type);
  return loader;
}

4.5.3 扩展 ExtensionLoader 加载对象构造器

ExtensionLoader 扩展加载器是比较复杂的,实现内容也比较多,这里先来看下 ExtensionLoader 的构造器,代码如下:

ExtensionLoader(Class<?> type, ExtensionDirector extensionDirector, ScopeModel scopeModel) {
  // 当前要加载的扩展类型
  this.type = type;
  // 创建扩展加载器的扩展访问器对象
  this.extensionDirector = extensionDirector;
  // 从扩展访问器中获取扩展执行前后的回调器
  this.extensionPostProcessors = extensionDirector.getExtensionPostProcessors();
  // 创建实例化策略对象
  initInstantiationStrategy();
  // 若当前扩展类型为扩展注入器类型则设置当前注入器变量为空,否则的话获取一个扩展注入器扩展对象
  this.injector = (type == ExtensionInjector.class ? null : extensionDirector.getExtensionLoader(ExtensionInjector.class).getAdaptiveExtension());
  // 创建 Activate 注解的排序器
  this.activateComparator = new ActivateComparator(extensionDirector);
  this.scopeModel = scopeModel;
}

先具体来看创建实例化策略对象代码:initInstantiationStrategy

private void initInstantiationStrategy() {
  // 初始化 ScopeModel 域模型对象时为扩展访问器添加了这个域模型扩展处理器对象 ScopeModelAwareExtensionProcessor
  // 这个类型实现了 ScopeModelAccessor 域模型访问器,可以用来获取域模型对象
  instantiationStrategy = extensionPostProcessors.stream()
    .filter(extensionPostProcessor -> extensionPostProcessor instanceof ScopeModelAccessor)
    .map(extensionPostProcessor -> new InstantiationStrategy((ScopeModelAccessor) extensionPostProcessor))
    .findFirst()
    .orElse(new InstantiationStrategy());
}

再看 ExtensionInjector 扩展对象的获取

/*
 * 1) 扩展类型肯定不是 ExtensionInjector 类型,这里必定会为每个非扩展注入 ExtensionInjector 类型创建一个 ExtensionInjector 类型的扩展对象
 * 2) 代码会走 extensionDirector.getExtensionLoader(ExtensionInjector.class) 这一步进去之后的代码在 4.5.2 介绍过了
 *    此处会创建一个扩展加载器 ExtensionLoader 用于创建 ExtensionInjector 类型
 * 3) getAdaptiveExtension() 这个方法就是通过扩展加载器获取具体的扩展对象的方法
 */
this.injector = (type == ExtensionInjector.class ? null : extensionDirector.getExtensionLoader(ExtensionInjector.class).getAdaptiveExtension());

image-20250519220113855

参考文献

https://cn.dubbo.apache.org/zh-cn/docsv2.7/dev/design/

https://www.ktyhub.com/zh/chapter_dubbo/4-extension-init/

vnjohn

作者

vnjohn

后端研发工程师。喜欢探索新技术,空闲时也折腾 AIGC 等效率工具。 可以在 GitHub 关注我了解更多,也可以加我微信(vnjohn) 与我交流。