Dubbo2 巩固教程之三

大纲

前言

学习资源

Dubbo 深入理解

服务治理的源码剖析

版本说明

组件版本说明
Dubbo2.6.6在阅读 Dubbo 源码时要注意,不同版本由于协议升级、SPI 改动、注册中心增强等因素,底层实现会出现细微差异;版本跨度越大,差异通常越明显。

基础概念

使用 Dubbo 开发时,可能会遇到以下问题:

  • (1) 服务接口粒度较粗时,如何实现读写场景的分离?
  • (2) 查询接口返回列表时,如何区分单条查询与多条查询的调用场景?
  • (3) 运行过程中,如果需要为某个应用额外增加服务实例,该如何实现?
  • (4) 运行过程中,如果需要动态调整服务权重,该如何实现?
  • (5) 运行过程中,如何需要动态调整服务的负载均衡策略,该如何实现?
  • (6) 如何在不停服的情况下发布新的服务版本?

Dubbo 的服务治理主要用于在运行时动态调整服务的行为和调用选址策略,从而实现限流、权重调整、路由控制等能力。

Dubbo 的服务治理(包括条件路由、标签路由、黑白名单、动态配置、权重调整、负载均衡等),都支持通过 Dubbo-Admin 服务治理控制台进行配置(动态调整),如下图所示:

思考问题

  • Dubbo 如何实现灰度发布、蓝绿发布、红黑发布、滚动发布、金丝雀发布、A/B 测试呢?
  • Dubbo 本身是服务治理框架,不负责流量调度,但它提供了条件路由 (ConditionRouter)、标签路由(TagRouter)、动态配置等机制,使得可以基于这些能力实现各种灰度与流量控制策略。

服务暴露

服务暴露的流程
  • 1、读取配置

    • Spring 启动 → 解析 @DubboService / <dubbo:service> → 生成 ServiceBean。
  • 2、初始化 ServiceBean

    • ServiceBean 触发 afterPropertiesSet() → 准备接口、实现类、协议、端口等信息。
  • 3、导出服务(Export)

    • 调用 ServiceConfig.export() → 进入真正的暴露逻辑。
  • 4、本地导出服务(可选)

    • 如果 Provider 配置了 scope=local(或旧版本的写法 scope=injvm) → 导出服务到本地 JVM,通过 InjvmProtocol 将服务放入本地内存 Map。
  • 5、远程导出服务

    • doExportUrls() → 选择协议(如 dubbo
    • 调用 DubboProtocol.export() → 创建 Exporter 并打开 Netty Server 监听端口。
  • 6、注册中心注册服务

    • 如果有 Registry(比如 ZooKeeper) → 调用 ZookeeperRegistry.register() → 将 URL 节点写入 /dubbo/${serviceInterface}/providers/
  • 7、启动完成,写入元数据(Metadata)

    • MetadataService 写入元数据 → 用于服务治理和服务消费者订阅。

服务提供者的配置
  • Dubbo 服务提供者的配置信息如下图所示:

服务暴露的入口方法
  • Dubbo 服务暴露的入口方法是 ServiceConfig.export(),可以从这个方法入手阅读 Dubbo 服务暴露的底层源码实现
1
2
3
4
5
6
7
8
import org.apache.dubbo.config.ServiceConfig;

ServiceConfig<DemoService> service = new ServiceConfig<>();

// ...(省略其他赋值代码)

// 暴露及注册服务
service.export();
服务暴露的 URL 组装
  • Dubbo 负责组装并导出服务 URL 的方法是 ServiceConfig.doExportUrlsFor1Protocol()(部分核心代码如下图所示)。该方法的主要作用:

    • 为单个协议(Protocol)生成并导出服务 URL(比如 dubbo://127.0.0.1:20880/com.demo.service.DemoService?anyhost=true...
    • 完成服务的本地导出 + 远程导出逻辑
    • 注册服务到注册中心(Registry)
    • 处理协议相关的参数(比如:权重、tokentimeout)等配置

  • Dubbo 中 URL 是一个非常重要的契约,所有扩展点都要遵守。

  • 所有扩展点参数都包含 URL 参数,URL 作为上下文信息贯穿了整个扩展点设计体系。

  • URL 采用标准格式:protocol://username:password@host:port/path?key1=value1&key2=value2...

    • 比如:dubbo://127.0.0.1:20880/com.demo.service.DemoService?anyhost=true&application=provider-application&dubbo=2.0.2&dynamic=true&generic=false&side=provider...

提示

Dubbo 将服务注册到 ZooKeper 注册中心后,ZooKeper 注册中心里面的数据存储结构和数据格式可以看 这里 的介绍。

多注册中心、多协议暴露服务
  • Dubbo 暴露服务时,支持多注册中心、多协议,具体方法是(部分核心代码如下图所示):
    • ServiceConfig.doExportUrls()
    • ServiceConfig.doExportUrlsFor1Protocol()

导出本地服务与远程服务

Exporter 导出本地服务

ServiceConfig.doExportUrlsFor1Protocol() 方法中,会调用 ServiceConfig.exportLocal() 方法将服务导出到本地,即导出服务到本地 JVM(injvm)。下图展示了 ServiceConfig.exportLocal() 方法的核心源码:

Exporter 导出远程服务

Dubbo 将服务导出到远程的流程较为复杂,包含 服务导出服务注册 两个阶段。当循环遍历到协议头为 registry://registryURL 时,就会进入 RegistryProtocol.export() 方法进行处理。下图展示了 RegistryProtocol.export() 方法的核心源码:

绑定服务端口的过程

RegistryProtocol.doLocalExport() 方法中,会执行服务端口的绑定(即启动 TCP 服务器),下图展示了 RegistryProtocol.doLocalExport() 方法的核心源码:

当使用的是 dubbo 协议时,RegistryProtocol.doLocalExport() 方法会调用 DubboProtocol.export() 方法,后续的方法调用链是 DubboProtocol.openServer() -> DubboProtocol.createServer() -> Exchangers.bind() -> HeaderExchanger.bind() -> Transporters.bind() -> NettyTransporter.bind() -> NettyServer() -> AbstractServer() -> AbstractServer.doOpen() -> NettyServer.doOpen()

服务注册的过程

Dubbo 将服务注册到注册中心(比如 Zookeeper)的方法调用链是 RegistryProtocol.export() -> ZookeeperRegistry.register()。下图展示了 RegistryProtocol.export() 方法的核心源码:

服务暴露总结

Dubbo(2.7.x)服务暴露的时序图(源自 Dubbo 官方文档)如下所示:

Dubbo(2.6.6)服务暴露的完整调用链如下(仅供参考,并非绝对严谨):

1
2
3
4
5
6
7
8
9
10
11
12
13
ServiceConfig.export()                                 ─► 服务暴露入口
└─ ServiceConfig.doExport() ─► 处理延迟暴露、状态检查,真正进入导出流程
└─ ServiceConfig.doExportUrls() ─► 构建所有需要导出的 URL(包括本地导出与远程导出)
└─ ServiceConfig.doExportUrlsFor1Protocol() ─► 针对单个协议执行导出流程
└─ Protocol$Adaptive.export() ─► 选择具体协议,SPI 自适应扩展,根据 registry:// 选择 RegistryProtocol
└─ RegistryProtocol.export() ─► 进入注册中心协议处理流程(服务注册核心位置)
└─ doLocalExport(originInvoker) ─► 执行本地服务导出,创建 Exporter,启动协议层服务(如 DubboProtocol + NettyServer)
└─ DubboProtocol.export() ─► 构建 Exporter、准备服务暴露逻辑
└─ new NettyServer(...) ─► 创建底层网络服务器(默认基于 Netty)
└─ NettyServer.doOpen() ─► 真正绑定端口,启动 Netty 服务器,开始监听请求
├─ registry = registryFactory.getRegistry() ─► 通过 SPI 创建 / 获取对应的 Registry 实例(如 ZookeeperRegistry)
├─ registry.register(providerUrl) ─► 将服务 URL 注册到注册中心(写入 Zookeeper)
└─ 返回 Exporter(最终服务暴露完成)

SPI 扩展机制

SPI 在服务暴露中的应用
  • 在 Dubbo 服务暴露的源码中,难以理解的地方(以下源码位于 ServiceConfig.doExportUrlsFor1Protocol()

    1
    2
    3
    4
    5
    // Invoker、Exporter 是什么? 为什么 proxyFactory、protocol 能创造它们?
    Invoker<?> invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, registryURL.addParameterAndEncoded(Constants.EXPORT_KEY, url.toFullString()));
    DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this);
    Exporter<?> exporter = protocol.export(wrapperInvoker);
    exporters.add(exporter);
  • Invoker 与 Exporter

    • Invoker 是实体域,作为 Dubbo 的核心模型,其他模型都向它靠拢或转换成它。它代表一个可执行体,能够将所有需要代理执行的方法,用 Invoker 进行抽象和转换。
    • Exporter 是一个服务暴露控制接口,用于获取暴露的 Invoker,以及注销暴露的 Invoker
  • API 与 SPI

    • Dubbo 框架有两类用户:框架使用者和框架扩展开发者。
    • 为了对这两类用户进行隔离,使用者通过 API 来使用框架,开发者通过 SPI 来对框架进行扩展。
    • 使用者无需从编码层面知道扩展类型,只需配置即可;扩展者也能很方便地扩展功能,不需要考虑适应不同的业务代码场景。
    • Dubbo 没有采用 JDK 内置的 SPI 机制,而是自己实现了一套 SPI 机制。
SPI 自适应扩展点的介绍
  • Dubbo SPI 自适应扩展的介绍
    • Dubbo SPI 自适应扩展的作用是:在运行时根据参数值动态决定采用哪个扩展点实现类。
    • Dubbo 中有多种类型的扩展点,例如协议、集群容错、负载均衡、注册中心、序列化等。这些扩展点在运行时获取参数的方式并不统一:有的依赖 URL 参数名获取参数值,有的在没有 URL 信息时只能通过 Invocation 获取方法级参数。
    • 为了解决不同扩展点参数来源不一致的问题
      • Dubbo 通过 Adaptive(自适应)动态代码生成机制自动生成代理类,比如 Dubbo 自动生成的 Protocol$Adaptive 代理类的代码示例可以看 这里
      • Dubbo 自动生成的代理类,可以在运行时根据实际上下文(如 URL、InvocationReferenceConfigServiceConfig 等)灵活选择具体扩展实现,从而屏蔽参数来源差异,保证扩展点能够自适应地工作。

  • Dubbo SPI 自适应扩展的使用
    • 在需要进行自适应的扩展类或接口方法标注 @Adaptive 注解。
    • @Adaptive 注解在接口方法上(最常见)
      • Dubbo 会为该接口方法生成代理逻辑,实现运行时根据参数动态选择具体扩展实现。
    • @Adaptive 注解在扩展类上(较少使用)
      • Dubbo 不会为该扩展类生成代理类;
      • 这种情况在 Dubbo 中很少见,目前仅有两个扩展类标注了 @Adaptive,分别是 AdaptiveCompilerAdaptiveExtensionFactory,表示这些扩展类的加载逻辑由人工编码(静态编码)完成。

  • Dubbo SPI 自适应扩展的实现
SPI 机制的使用示例
  • Dubbo 内部使用 SPI 机制的源码案例

  • 自定义 Dubbo SPI 扩展的基本步骤(例如,自定义协议扩展实现)

    • (1) 提供 SPI 插件的扩展实现类
      • 提供一个 Java 类实现 org.apache.dubbo.rpc.Protocol 接口
        1
        2
        3
        4
        5
        6
        7
        8
        9
        package com.spi.demo;
        import org.apache.dubbo.rpc.Protocol;

        /**
        * 实现自己的 Dubbo 协议
        */
        public class CustomizedProtocol implements Protocol {
        // ...
        }
    • (2) 在指定的文件里面配置扩展实现类
      • 在应用的 resources/META-INF/dubbo/ 目录下创建 org.apache.dubbo.rpc.Protocol 文件,并在文件中添加如下配置内容:
        1
        customized=com.spi.demo.CustomizedProtocol
      • 文件名必须为 SPI 接口的全限定名,例如:META-INF/dubbo/org.apache.dubbo.rpc.Protocol,对应你要扩展的接口。
      • 文件内容必须为 key=value 形式,其中 key 为扩展名(可自定义,建议添加特定前缀避免与 Dubbo 内置实现冲突),value 为扩展实现类的全限定名。
    • (3) 通过 Dubbo 配置启用自定义协议实现
      • 在应用中修改 Dubbo 的协议配置,告诉 Dubbo 框架使用自定义协议:
        1
        2
        3
        4
        # 使用 SpringBoot 时,可修改 application.yml 或 application.properties 配置文件
        dubbo
        protocol
        name: customized
      • 或者,使用原生 API 告诉 Dubbo 框架使用自定义协议:
        1
        2
        ProtocolConfig protocol = new ProtocolConfig();
        protocol.setName("cutomized");
SPI 机制的核心注解

Dubbo SPI 机制有两个核心注解,分别是 @Adaptive@Activate

  • @Adaptive 注解(自适应)
    • 主要作用
      • 表示该扩展类或接口方法需要自适应扩展,Dubbo 会在运行时根据 URL 或其他条件动态选择具体扩展实现。
    • 常见使用方式
      • @Adaptive 标注在接口方法上(最常见)
        • 表示由 Dubbo 自动生成 Xxx$Adaptive 代理类
        • 方法内部会根据 URL 参数在运行时选择具体扩展实现
        • 使用例子:
          1
          2
          3
          4
          5
          6
          public interface Protocol {

          @Adaptive({"protocol", "defaultProtocol"})
          Exporter export(Invoker invoker);

          }
          • 当上面调用 export() 方法时,Dubbo 会根据 URL 的 protocoldefaultProtocol 参数决定使用哪个协议实现
      • @Adaptive 标注在扩展类上(较少使用)
        • 表示该扩展类是一个手工编写的自适应扩展类
        • Dubbo 将直接使用这个扩展类,而不会再自动生成代理类
        • 一般用于非常复杂的场景,比如需要手写逻辑替代 Dubbo 自动生成代理类
        • 目前 Dubbo 中仅有两个扩展类标注了 @Adaptive,分别是 AdaptiveCompilerAdaptiveExtensionFactory,表示这些扩展类的加载逻辑由人工编码(静态编码)完成
        • 使用例子:
          1
          2
          3
          4
          5
          6
          7
          8
          9
          @Adaptive
          public class CustomAdaptiveCompiler implements Compiler {

          @Override
          public Class<?> compile(String code, ClassLoader loader) {
          // 自定义代码编译逻辑
          }

          }
    • 使用注意事项
      • 接口上不能标注 @Adaptive
      • 接口方法上可以标注 @Adaptive,表示使用 Dubbo 自动生成的代理类,适用大多数场景
      • 扩展类上可以标注 @Adaptive,表示使用手写的自适应逻辑,适用特殊复杂场景

  • @Activate 注解(自动激活)
    • 主要作用
      • 表示当扩展类被自动加载时,满足 groupvalueorder 等条件,该扩展会自动加入扩展链,无需手动在配置中指定扩展名。
    • 常见使用方式
      • @Activate 标注在扩展类上(最常见)
        • 扩展类在满足 Activate 条件时自动激活
        • 一般用于 Filter、Router、ExporterListener、Registry 等扩展点
        • 使用例子:
          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          @Activate(group = {"provider"}, order = 10)
          public class MyProviderFilter implements Filter {

          @Override
          public Result invoke(Invoker<?> invoker, Invocation invocation) {
          // 自定义过滤逻辑
          return invoker.invoke(invocation);
          }

          }
      • @Activate 标注在接口方法上(较少使用)
        • 表示该接口方法返回的扩展类实例在调用时可自动激活
        • 可结合 URL 参数或 groupvalueorder 条件进行动态控制
        • 使用例子:
          1
          2
          3
          4
          5
          6
          public interface SomeFactory {

          @Activate(value = {"feature"}, group = "consumer")
          Extension create();

          }
    • 典型使用 @Activate 自动激活的扩展点(最常见场景)
      • Filter 自动生效(过滤器)
      • Router 自动生效(路由)
      • ExporterListener 自动生效(监听服务暴露)
      • Registry(如注册中心相关监听、通知)自动生效
    • 可使用 @Activate 激活,但通常是通过 URL 指定或者明确选择的的扩展点
      • Cluster(有些装饰逻辑可能自动封装,但多数是由 Dubbo 主流程显式选择)
      • Protocol(支持 @Activate,但较少用于自动激活,一般是 URL 或显式选择)
      • ProxyFactory(可自动激活,但通常通过指定实现选择)
    • 使用注意事项
      • 接口上不能标注 @Activate

总结

  • @Adaptive(自适应)的作用:让扩展在运行时根据 URL 或条件动态选择具体扩展实现;标注在方法上,则表示由 Dubbo 自动生成代理类;标注在类上,则表示使用手写的自适应逻辑。
  • @Activate(自动激活)的作用:让扩展类在满足 Activate 条件时自动激活加入调用链;可以省略,但省略后不会自动激活,必须通过扩展名主动加载,例如: extensionLoader.getExtension("customizedProtocol");
SPI 机制的实现原理
  • (1) 使用 @SPI 注解
    • 在接口上标注 @SPI 注解,表示这个接口是 Dubbo 的扩展点
    • @SPI 注解可以设置参数:
      • 比如 @SPI("defaultName"):指定该扩展点的默认扩展名
        • 当调用 getDefaultExtension() 或未明确指定扩展名时,会使用此默认实现
      • 如果 @SPI 注解不设置参数,则该扩展点没有默认实现,必须在调用时明确指定扩展名。
  • (2) 创建扩展配置文件
    • 扩展配置文件存放位置:META-INF/dubbo/接口全限定名文件
    • 文件名称是:接口全限定名
    • 文件内容是:扩展名 = 扩展类全限定名
  • (3) 由 ExtensionLoader 类加载扩展
    • 读取扩展配置文件
    • 建立 “扩展名 → 扩展类” 映射
    • 完成实例化、缓存、生命周期管理
    • 首次使用时才加载(即懒加载)
  • (4) 支持通过 @Adaptive 注解动态选择扩展
    • Dubbo 会自动生成代理类,根据 URL 参数在运行时选择具体扩展实现
  • (5) 支持通过 @Activate 注解自动激活扩展
    • 根据 groupvalueorder 等条件自动激活扩展,可实现过滤器链(Filter)等机制
SPI 机制的加载流程
  • Dubbo SPI 机制加载扩展的核心步骤:
    • (1) 读取并解析配置文件
    • (2) 缓存所有扩展实现类
    • (3) 基于用户执行的扩展名,实例化对应的扩展实现类
    • (4) 执行扩展实例属性的 IOC 注入(基于 Setter 注入),以及实例化扩展的包装类,实现 AOP 特性

  • Dubbo SPI 机制加载扩展的整个流程:
SPI 机制的源码剖析
  • Dubbo SPI 机制的核心实现源码

    • 核心实现源码位于 com.alibaba.dubbo.common.extension.ExtensionLoader
      • 负责加载扩展配置文件、创建扩展实例、缓存实例、处理依赖注入,以及生成 Adaptive 代理对象或包装 Wrapper 扩展等
    • ExtensionLoader 类的核心方法有以下几个(不限于):
      • getExtensionLoader() —— 获取指定接口类型的 ExtensionLoader 实例,是 SPI 的入口。
      • getExtensionClass() —— 获取指定扩展名对应的扩展实现类。
      • loadExtensionClasses() —— 加载接口对应的所有扩展实现类,解析 META-INF/dubbo 配置文件。
      • getExtension() —— 根据扩展名获取单个扩展实例(普通扩展)。
      • getActivateExtension() —— 获取符合条件的自动激活扩展集合。
      • createExtension() —— 创建普通扩展实例,并注入其依赖扩展。
      • createAdaptiveExtension() —— 创建 Adaptive 代理对象,实现方法级别自适应扩展逻辑。
      • createAdaptiveExtensionClassCode() —— 生成 Adaptive(自适应)动态代理类的 Java 源码,用于根据 URL 参数选择具体扩展实现。

  • Dubbo SPI 机制的源码剖析

    • (1) 通过反射创建扩展类实例

      • Dubbo 使用 Class.newInstance() 或构造函数反射来创建扩展类对象实例。
      • 扩展类实例化的逻辑集中在 ExtensionLoader.createExtension() 中。
    • (2) 依赖注入:injectExtension() 方法

      • 扩展类实例创建后,Dubbo 会遍历其所有 setter 方法。
      • 如果某个 setter 方法的参数类型是另一个扩展点接口:
        • 则通过 ExtensionLoader.getExtension() 获取对应扩展实例
        • 调用 setter 方法将其注入
      • 这相当于一个轻量级的 IOC 容器,但只对扩展点生效。
    • (3) 包装类(Wrapper)的处理机制

      • Dubbo 支持 “包装类” 扩展机制,用于为扩展点添加通用逻辑(如 Filter 链、Cluster 封装)。
      • wrapper 类特征:
        • 它有一个构造函数参数刚好为当前扩展接口,例如:
          1
          public XxxWrapper(Xxx extension) {}
        • Dubbo 以此判断该类是 Wrapper,而不是普通扩展实现。
    • (4) Wrapper 的装饰顺序和依赖注入

      • Dubbo 会先创建原始扩展实例(realExtension)。
      • 然后按定义顺序用多个 Wrapper 层层包装实例:
        1
        Wrapper3(Wrapper2(Wrapper1(realExtension)))
      • 每个 Wrapper 创建后也会走 injectExtension(),同样支持注入依赖扩展点。
    • (5) Wrapper 的核心作用

      • 封装通用逻辑,例如:
        • Filter 责任链
        • Cluster 对 Invoker 的封装
        • 监控、日志、限流等逻辑
      • 使用装饰器模式,不修改原始扩展类即可增强行为。
    • (6) 最终返回的扩展实例

      • 扩展实例 = 多层 Wrapper + 真实扩展类
      • 所有依赖扩展均自动注入完成
      • 整个对象结构由 ExtensionLoader 全面管理

Dubbo SPI 机制源码剖析的总结

在 Dubbo SIP 机制中,通过 Class 反射类来构造 Class 对象实例,injectExtension() 方法通过 setter 注入扩展类中依赖的其他扩展点。包装类 Wrapper 封装了通用的逻辑,通过有无当前扩展接口参数的构造函数来判断,并注入依赖扩展。

Dubbo 中的 Invoker

Invoker 的概念
  • Invoker 是 Dubbo 的核心模型,也是实体域,其它模型都围绕它展开或可以转换为它。
  • Invoker 表示一个可执行体,可以对其发起 invoke() 调用,它可能是本地实现、远程实现,也可能是集群实现。在 Dubbo 中,所有需要代理执行的方法都可以通过 Invoker 进行抽象和转换。
  • Invoker 是由 ProxyFactory 创建的,Dubbo 默认的 ProxyFactory 实现类是 JavassistProxyFactory,即默认使用 Javassist 字节码操作技术来实现动态代理。下图展示了 JavassistProxyFactory.getInvoker() 方法的核心源码:

Wrapper 的概念
  • Wrapper 的核心概念
    • 主要作用:
      • 对目标类的方法和属性进行统一封装,提高方法调用和属性访问的效率。
    • 实现原理:
      • 通过动态生成字节码(默认基于 Javassist),避免依赖反射调用,从而提升方法调用性能
    • 核心功能:
      • 快速调用目标类的方法(通过 invokeMethod() 调用)
      • 快速访问目标类的字段
      • 缓存生成的 Wrapper 实例,减少重复生成字节码的开销
    • 应用场景:
      • 在 Dubbo 中,用于对服务接口或实现类进行统一代理和方法调用
      • 提高 RPC 调用和本地方法调用的效率

  • Wrapper 的核心方法
    • invokeMethod(Object instance, String methodName, Class<?>[] parameterTypes, Object[] args)
      • 作用:通过 Wrapper 对目标对象的方法进行调用分发。
      • 说明:Wrapper 会根据传入的对象(instance)、方法名(methodName)、参数类型和参数值,将调用分发到具体的方法实现上,从而实现对目标类方法的统一调用封装,避免直接使用反射的性能开销。
    • getWrapper(Class<?> c)
      • 作用:获取指定类对应的 Wrapper 实例(通常是已缓存的 Wrapper)。
      • 说明:调用 getWrapper() 时,若 Wrapper 已经生成,会直接返回缓存的实例;否则,会调用 makeWrapper() 动态生成一个新的 Wrapper。通过缓存机制,可以减少重复生成 Wrapper,提高性能。
    • makeWrapper(Class<?> c)
      • 作用:为指定的类生成一个 Wrapper 类实例。
      • 说明:Wrapper 内部通过动态生成字节码(默认使用 Javassist)封装目标类的方法和属性,从而提供快速的方法调用和属性访问能力。生成后的 Wrapper 可以高效地对目标类进行方法调用和字段操作,而不需要每次都通过 Java 反射来实现。

  • Invoker 与 Wrapper 的关系
    • Invoker 用来执行方法调用,而 Wrapper 用来辅助 Invoker 更高效地调用目标对象的方法。
      • Wrapper:通过字节码技术(默认使用 Javassist)为目标类动态生成高性能的 “方法调用辅助类”,避免使用反射来调用方法。
      • Invoker:Dubbo 的核心执行体,通过 invoke() 调用目标对象的方法。
    • 简而言之,Invoker 在执行方法调用时,会使用 Wrapper 动态生成的快速调用代码来调目标对象的方法。

参考资料