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

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);
        }
    }

http://www.kler.cn/a/587938.html

相关文章:

  • 从零开始写C++3D游戏引擎(开发环境VS2022+OpenGL)之十一 从打光到材质 细嚼慢咽逐条读代码系列
  • Oracle Database 11g、12c、18c、19c、21c、22c 与 23AI 各版本差异、优缺点详解
  • 结构体定义与应用
  • C++特性——智能指针
  • 基于SpringBoot3+Druid数据库连接池与外部PostgreSQL的Kubernetes Pod YAML全解析
  • Java集合 - HashMap
  • 自动化测试脚本
  • Hive SQL 精进系列:PERCENTILE_APPROX 搞定分位数
  • 电磁兼容|RC电路
  • Hooka:多功能 Shellcode 加载器生成工具详解
  • harmonyOS NEXT开发与前端开发深度对比分析
  • 【linux篇】--linux常见指令
  • MyBatis SqlSessionFactoryBuilder 的作用是什么?
  • Android 手机启动过程
  • R语言零基础系列教程-01-R语言初识与学习路线
  • Java 大视界 -- 基于 Java 的大数据实时流处理中的窗口操作与时间语义详解(135)
  • FPGA中级项目2——硬核 or 软核与FIFO的配置
  • 前端---初识HTML(前端三剑客)
  • ModelScope推理QwQ32B
  • 【QA】模板方法模式在Qt中有哪些应用?