1

1. 前言

在 Dubbo 框架中,服务消费者通过 XML 配置方式引用服务时,涉及多个模块之间的协作。

不放dubbo官方的设计图了,这里同样放一张自己画的服务消费者调用图,后面的介绍也是围绕这张图来的。

以下是服务消费者引用服务时,各个模块之间的源码方法调用关系的详细说明。

2. 简述过程

dubbo-config-spring 项目模块中,dubbo 框架定义了 dubbo.xsd。业务使用时,可以基于 定义好的标签(<dubbo:reference>等),在 xml 中配置要发布的服务。

这部分内容可以查看前面写的 《Spring XML自定义命名空间》

服务提供者在启动时,DubboNamespaceHandler 中会根据 XML 配置中的 <dubbo:reference> 标签引用服务,整个过程大致如下:

  1. 解析 XML 配置

    • 解析 <dubbo:reference> 标签,创建 ReferenceConfig 对象。
  2. 服务引用

    • 调用 ReferenceConfig.get() 方法,开始服务引用过程。
  3. 协议引用

    • ReferenceConfig.get() 方法内部调用 Protocol.refer() 方法,通过具体的协议实现服务的引用。
  4. 服务发现和负载均衡

    • 通过 RegistryDirectory 进行服务发现,并通过 ClusterLoadBalance 实现负载均衡。
  5. 代理创建

    • 使用 ProxyFactory 创建服务接口的代理对象。

3. ReferenceConfig 模块

  • 作用:负责服务引用的配置和管理,是服务引用的入口。
  • 关键方法ReferenceConfig.get()
public class ReferenceConfig<T> {
    private volatile T ref;

    public synchronized T get() {
        if (ref == null) {
            init();
        }
        return ref;
    }

    private void init() {
        // 调用 Protocol.refer()
        Invoker<?> invoker = protocol.refer(interfaceClass, url);
        // 创建代理对象
        ref = proxyFactory.getProxy(invoker);
    }
}

4. Protocol 模块

  • 作用:负责服务的导出和引用。
  • 关键方法Protocol.refer()
public interface Protocol {
    <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException;
}

5. RegistryProtocol.refer()

  • 作用:处理服务发现和引用相关的逻辑。
  • 调用关系

    1. 获取注册中心:通过 RegistryFactory 获取 Registry 实例。
    2. 创建服务目录:创建 RegistryDirectory,用于管理服务提供者的地址列表。
    3. 订阅服务:通过 Registry 订阅服务提供者信息。
    4. 集群合并:通过 Cluster.join() 将多个服务提供者的 Invoker 合并为一个集群 Invoker
public class RegistryProtocol implements Protocol {
    @Override
    public <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException {
        // 1. 获取注册中心
        Registry registry = registryFactory.getRegistry(url);
        // 2. 创建服务目录
        RegistryDirectory<T> directory = new RegistryDirectory<>(type, url);
        // 3. 订阅服务提供者
        directory.setRegistry(registry);
        directory.subscribe(subscribeUrl);
        // 4. 返回集群 Invoker
        return cluster.join(directory);
    }
}

6. Cluster 模块

  • 作用:负责将多个服务提供者的 Invoker 合并为一个集群 Invoker,实现负载均衡和容错。
  • 关键方法Cluster.join()
public interface Cluster {
    <T> Invoker<T> join(Directory<T> directory) throws RpcException;
}

7. Invoker 模块

  • 作用:表示一个可调用的服务引用,是服务调用的核心模型。
  • 关键方法Invoker.invoke() 用于执行远程调用。
public interface Invoker<T> {
    Result invoke(Invocation invocation) throws RpcException;
}

8. ProxyFactory 模块

  • 作用:负责创建服务接口的代理对象。
  • 关键方法ProxyFactory.getProxy()
public interface ProxyFactory {
    <T> T getProxy(Invoker<T> invoker) throws RpcException;
}

9. LoadBalance 模块

  • 作用:提供负载均衡策略,选择合适的 Invoker 进行调用。
  • 关键方法LoadBalance.select()
public interface LoadBalance {
    <T> Invoker<T> select(List<Invoker<T>> invokers, URL url, Invocation invocation) throws RpcException;
}

10. 总结

在 Dubbo 服务消费者的引用过程中,多个模块协同工作:

  • ReferenceConfig:负责服务引用的配置和入口。
  • Protocol 和 Invoker:负责服务的引用和调用。
  • Registry 和 Directory:负责服务的发现和动态管理。
  • Cluster 和 LoadBalance:负责负载均衡和容错。
  • ProxyFactory:负责创建服务接口的代理对象。
图示化流程
ReferenceConfig.get() 
    └── RegistryProtocol.refer()
          └── Registry.getRegistry()
          └── RegistryDirectory.subscribe()
          └── Cluster.join()
                └── LoadBalance.select()
    └── ProxyFactory.getProxy()
  1. ReferenceConfig.get()

    • 解析服务引用配置,准备服务引用。
    • 调用 Protocol.refer() 进行服务引用。
  2. RegistryProtocol.refer()

    • 获取注册中心并创建服务目录。
    • 订阅服务提供者信息。
    • 通过 Cluster.join() 返回集群 Invoker。
  3. Cluster.join()

    • 合并多个服务提供者的 Invoker,实现负载均衡。
  4. ProxyFactory.getProxy()

    • 创建服务接口的代理对象,供消费者使用。
  5. LoadBalance.select()

    • 在服务调用时,选择合适的 Invoker 进行调用。

KerryWu
641 声望159 粉丝

保持饥饿


引用和评论

0 条评论