当前位置: 首页 > news >正文

Dubbo 服务发现

总览

学习 Dubbo 的服务发现机制,可以从以下几方面入手:

  1. 注册中心的配置
  2. 服务的注册
  3. 客户端拉取服务列表
  4. 服务列表的本地缓存
  5. 服务提供者列表变更的监听机制
  6. 服务发现的接口设计

注册中心的配置

Dubbo 通过解析用户配置决定使用的注册中心。比如用户配置了 zookeeper://127.0.0.1:2181,Dubbo 在导出服务时解析出 name = zookeeper,便拿着这个名字到 ExtensionLoader 加载得到 ZookeeperServiceDiscoveryFactory,该工厂类生产出 ZookeeperServiceDiscovery,后续 ServiceDiscoveryRegistry 便可以通过调用 ZookeeperServiceDiscovery 的 doRegister 方法注册服务。

服务的注册

Spring 执行 refresh 方法后会触发 Dubbo 将服务注册到注册中心。

Spring 的 AbstractApplicationContext 执行 refresh 方法返回前,会发布 ContextRefreshedEvent, DubboBootstrapApplicationListener 接收到 ContextRefreshedEvent 后,会初始化并导出服务,最后将服务注册到注册中心。

/**
 * An ApplicationListener to control Dubbo application.
 */
public class DubboDeployApplicationListener
        implements ApplicationListener<ApplicationContextEvent>, ApplicationContextAware, Ordered {

    @Override
    public void onApplicationEvent(ApplicationContextEvent event) {
        if (nullSafeEquals(applicationContext, event.getSource())) {
            if (event instanceof ContextRefreshedEvent) {
                onContextRefreshedEvent((ContextRefreshedEvent) event);
            }
            ...
        }
    }

    private void onContextRefreshedEvent(ContextRefreshedEvent event) {
        ModuleDeployer deployer = moduleModel.getDeployer();
        Assert.notNull(deployer, "Module deployer is null");
        Object singletonMutex = LockUtils.getSingletonMutex(applicationContext);
        // start module
        Future future = null;
        synchronized (singletonMutex) {
            future = deployer.start();
        }

        ...
    }
}

ModuleDeployer 在 start 方法中调用了 registerServices 方法,完成了服务的注册。其调用链如下:

ModuleDeployer.registerServices -> ModuleDeployer.registerServiceInternal
-> ServiceConfigBase.register -> Exporter.register

其中,ModuleDeployer.registerServiceInternal 遍历 configManager 中的每一个服务,逐个对它们进行注册。

Exporter.register 实际调用的类视注册中心的不同而不同,以 ZooKeeper 为例,通过模版方法实现服务注册:

public abstract class FailbackRegistry extends AbstractRegistry {
    @Override
    public void register(URL url) {
        if (!shouldRegister(url)) {
            return;
        }
        super.register(url);
        removeFailedRegistered(url);
        removeFailedUnregistered(url);
        try {
            // Sending a registration request to the server side
            doRegister(url);
        } catch (Exception e) {
            Throwable t = e;

            // If the startup detection is opened, the Exception is thrown directly.
            boolean check = getUrl().getParameter(Constants.CHECK_KEY, true)
                    && url.getParameter(Constants.CHECK_KEY, true)
                    && (url.getPort() != 0);
            boolean skipFailback = t instanceof SkipFailbackWrapperException;
            if (check || skipFailback) {
                if (skipFailback) {
                    t = t.getCause();
                }
                throw new IllegalStateException(
                        "Failed to register " + url + " to registry " + getUrl().getAddress() + ", cause: "
                                + t.getMessage(),
                        t);
            } else {
                logger.error(
                        INTERNAL_ERROR,
                        "unknown error in registry module",
                        "",
                        "Failed to register " + url + ", waiting for retry, cause: " + t.getMessage(),
                        t);
            }

            // Record a failed registration request to a failed list, retry regularly
            addFailedRegistered(url);
        }
    }
}

doRegister 仅仅是在 Zookeeper 创建一个 ZNode(Zookeeper 文件系统中的节点):

    @Override
    public void doRegister(URL url) {
        try {
            checkDestroyed();
            zkClient.create(toUrlPath(url), url.getParameter(DYNAMIC_KEY, true), true);
        } catch (Throwable e) {
            throw new RpcException(
                    "Failed to register " + url + " to zookeeper " + getUrl() + ", cause: " + e.getMessage(), e);
        }
    }

相关文章:

  • 【Linux】五种 IO 模型与非阻塞 IO
  • K8s的部署
  • 深度学习部署到小程序
  • [RN 实践有效]Expo+cross-env配置项目环境变量
  • Linux项目自动化构建工具 - make/Makefile 练习 进度条 倒计时
  • 深入解析 FID:深度学习生成模型评价指标
  • netty中黏包,半包
  • Axure大屏可视化原型模板及素材:数据可视化的高效解决方案
  • PowerBI数据建模基础操作1:数据关系(基数、双向筛选、常规关系、有限关系)与星型架构(维度表、事实表)
  • 位运算(基础算法)
  • MATLAB中wildcardPattern函数用法
  • Mastering SAP Analytics Cloud - Empower Your Business Users
  • QListView、QListWidget、QTableView和QTableWidget
  • 得物 一面
  • 第2章 网络安全评估平台(网络安全评估)
  • 归并排序:数据排序的高效之道
  • 光场中的核心概念:Macro Pixel与SAI的深度解析与实例应用
  • float x_number 转换成char*
  • Topo2Seq:突破DETR局限,车道拓扑推理新高度
  • thefuck是如何帮助你提高命令行效率
  • 巴基斯坦外交部:印度侵略行径侵犯巴主权
  • 预告:央行等部门将发声,介绍“一揽子金融政策支持稳市场稳预期”有关情况
  • 重温经典|中国首部剪纸动画片《猪八戒吃瓜》创作始末
  • 外交部:中方和欧洲议会决定同步全面取消对相互交往的限制
  • 牛市早报|“五一”假期预计跨区域人员流动量累计14.67亿人次
  • 习近平对贵州毕节市黔西市游船倾覆事故作出重要指示