Dubbo 的服务暴露和引用过程是怎样的?

Dubbo 的 服务暴露(Export)服务引用(Refer) 是其核心流程,分别对应服务提供者(Provider)暴露服务 和 服务消费者(Consumer)引用远程服务的过程。整个过程高度依赖 Dubbo 的 SPI 机制、代理、注册中心和网络通信模块。


一、总体流程概览

Provider(服务提供者)                    Consumer(服务消费者)
       |                                          |
       | 1. 服务暴露(Service Export)            | 2. 服务引用(Service Refer)
       | → 本地暴露(JVM 内调用优化)             | → 创建代理对象
       | → 注册到注册中心                         | → 从注册中心订阅服务
       | → 启动网络服务器(Netty)监听调用         | → 接收服务变更通知
       |                                          |
       |<----------------------------------------|
       |               3. 远程调用(RPC)          |
       |---------------------------------------->|

二、服务暴露(Service Export)过程(Provider 端)

当 Provider 启动时,会将实现的服务接口暴露出去,供 Consumer 调用。

1. 配置解析

  • 通过 XML、注解(@DubboService)或 Java 配置加载服务信息:
    @DubboService
    public class UserServiceImpl implements UserService { ... }
    
  • 解析出:接口名、实现类、版本、分组、超时、权重、协议等。

2. 创建 Invoker

  • Dubbo 抽象了 Invoker 接口,代表一个可执行的远程服务。
  • 通过代理工厂(ProxyFactory)为服务实现类创建 AbstractProxyInvoker
    Invoker<UserService> invoker = proxyFactory.getInvoker(serviceImpl, UserService.class, url);
    

3. 协议暴露(Protocol.export)

  • 根据配置的协议(如 dubbohttpgRPC)进行暴露。
  • 调用 Protocol 扩展点的 export() 方法:
    Exporter<UserService> exporter = protocol.export(invoker);
    
  • Dubbo 协议核心逻辑
    • 启动 Netty 服务器(默认端口 20880)
    • 绑定 NettyServer,监听请求
    • 建立连接、处理编解码(如 Hessian2)、反序列化调用请求

4. 注册到注册中心

  • 将服务元信息(URL)注册到注册中心(如 Nacos、ZooKeeper):
    dubbo://192.168.1.100:20880/com.example.UserService?
      version=1.0.0&
      group=user&
      timeout=5000&
      weight=100
    
  • 注册中心保存:服务名 → 多个 Provider 地址列表

5. 本地暴露(JVM 优化,可选)

  • 同时暴露一个本地 JVM 协议(injvm://),用于同一进程内的调用优化,避免网络开销。

三、服务引用(Service Refer)过程(Consumer 端)

Consumer 在启动时,会“引用”远程服务,生成一个本地代理对象,调用时透明发起远程调用。

1. 配置解析

  • 通过 @DubboReference 或 XML 配置声明引用的服务:
    @DubboReference
    private UserService userService;
    

2. 从注册中心订阅服务

  • 向注册中心发送订阅请求:
    subscribe: com.example.UserService:1.0.0
    
  • 注册中心返回当前可用的 Provider 列表(IP:Port + URL 参数)
  • Consumer 在本地缓存服务提供者列表

3. 监听服务变更

  • 注册监听器,监听 Provider 的上线/下线事件
  • 当 Provider 变化时,更新本地的 Invoker 列表(如新增、删除节点)

4. 创建 Invoker

  • 对每个 Provider 创建一个 DubboInvoker
  • 封装网络通信逻辑(Netty 客户端)
  • 所有 Invoker 被包装成一个 Directory(目录服务)

5. 集群容错包装(Cluster)

  • 通过 Cluster 扩展(如 FailoverCluster)将多个 Invoker 包装成一个 ClusterInvoker
  • 负责负载均衡、失败重试等逻辑

6. 生成代理对象(Proxy)

  • 使用代理工厂(JDK 动态代理、Javassist、ByteBuddy)生成代理对象

  • 当调用 userService.getUser(1) 时,实际调用的是代理逻辑

    public class $Proxy0 implements UserService {
        public User getUser(Long id) {
            // 被拦截,走远程调用逻辑
            return clusterInvoker.invoke(new RpcInvocation("getUser", ...));
        }
    }
    

四、关键组件协作图

[Provider]
   |
   ↓
ServiceConfig → Invoker → Protocol.export → NettyServer (监听)
   ↓
RegistryProtocol → 注册到 ZooKeeper/Nacos

[Consumer]
   |
   ↓
ReferenceConfig → RegistryProtocol.subscribe → 从注册中心获取 Provider 列表
   ↓
Directory → 多个 Invoker
   ↓
Cluster → ClusterInvoker(负载均衡 + 容错)
   ↓
ProxyFactory → 生成代理对象(proxy)
   ↓
userService → 透明调用

五、服务暴露与引用的核心类

类名作用
ServiceConfigProvider 端,控制服务暴露流程
ReferenceConfigConsumer 端,控制服务引用流程
ProxyFactory生成代理对象(SPI 扩展)
Protocol协议层,控制服务暴露和引用(SPI)
RegistryProtocol负责注册/订阅逻辑
Invoker远程调用的抽象
Exporter暴露后的引用,用于取消暴露
Cluster集群容错,包装多个 Invoker
LoadBalance从多个 Invoker 中选择一个

六、一次远程调用的完整流程(暴露 + 引用之后)

  1. Consumer 调用 userService.getUser(1)
  2. 代理对象拦截,封装为 RpcInvocation
  3. ClusterInvokerDirectory 获取可用 Invoker 列表
  4. LoadBalance 选择一个 Invoker(如随机)
  5. DubboInvoker 通过 Netty 发送请求(序列化:Hessian2)
  6. Provider 端 NettyServer 接收请求,反序列化
  7. 根据接口名、方法名反射调用本地实现
  8. 返回结果,反向传递给 Consumer
  9. Consumer 反序列化结果,返回给调用方

七、高级特性支持

特性实现方式
延迟暴露delay="5000",延迟 5 秒暴露
多协议暴露<dubbo:service protocol="dubbo,http"/>
多注册中心支持同时注册到 Nacos 和 ZooKeeper
本地存根(Stub)自定义本地逻辑预处理
异步调用支持 CompletableFuture
泛化调用不依赖接口,直接调用 GenericService

八、总结

阶段关键动作核心目标
服务暴露创建 Invoker → 启动 Netty → 注册到注册中心让服务可被发现和调用
服务引用订阅服务 → 创建 Invoker 列表 → 生成代理让调用像本地方法一样透明
远程调用代理拦截 → 负载均衡 → 网络通信 → 反射执行实现高性能 RPC

Dubbo 的服务暴露和引用,本质是:

  • 暴露:把本地服务变成可远程调用的网络服务
  • 引用:把远程服务变成可本地调用的代理对象

通过 注册中心 + 代理 + Invoker 抽象 + 协议扩展 实现了 透明化远程调用


📌 建议学习路径

  1. 阅读 ServiceConfig.export()ReferenceConfig.get() 源码
  2. 调试一次 Dubbo 启动过程
  3. 查看 DubboProtocolRegistryProtocol 实现
  4. 理解 InvokerExporter 的抽象意义

官方文档:https://dubbo.apache.org

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值