dubbo源码中设计模式——注册中心中工厂模式的应用

工厂模式的介绍

工厂模式提供了一种创建对象的方式,而无需指定要创建的具体类。

工厂模式属于创建型模式,它在创建对象时提供了一种封装机制,将实际创建对象的代码与使用代码分离。

应用场景:定义一个创建对象的接口,让其子类自己决定实例化哪一个工厂类,工厂模式使其创建过程延迟到子类进行。

工厂模式包含以下几个核心角色:

  • 抽象产品(Abstract Product):定义了产品的共同接口或抽象类。它可以是具体产品类的父类或接口,规定了产品对象的共同方法。
  • 具体产品(Concrete Product):实现了抽象产品接口,定义了具体产品的特定行为和属性。
  • 抽象工厂(Abstract Factory):声明了创建产品的抽象方法,可以是接口或抽象类。它可以有多个方法用于创建不同类型的产品。
  • 具体工厂(Concrete Factory):实现了抽象工厂接口,负责实际创建具体产品的对象。

UML模型图如下:

dubbo源码中的应用

所有的注册中心实现,都是通过对应的工厂创建的。工厂类之间的关系如图:

AbstractRegistryFactory 实现了 RegistryFactory 接口的 getRegistry(URL url)方法,是一个通用实现,主要完成了加锁,以及调用抽象模板方法createRegistry(URL url)创建具体实现等操作,并缓存在内存中。

java 复制代码
public Registry getRegistry(URL url) {
        if (registryManager == null) {
            throw new IllegalStateException("Unable to fetch RegistryManager from ApplicationModel BeanFactory. "
                    + "Please check if `setApplicationModel` has been override.");
        }

        Registry defaultNopRegistry = registryManager.getDefaultNopRegistryIfDestroyed();
        if (null != defaultNopRegistry) {
            return defaultNopRegistry;
        }

        url = URLBuilder.from(url)
                .setPath(RegistryService.class.getName())
                .addParameter(INTERFACE_KEY, RegistryService.class.getName())
                .removeParameter(TIMESTAMP_KEY)
                .removeAttribute(EXPORT_KEY)
                .removeAttribute(REFER_KEY)
                .build();

        String key = createRegistryCacheKey(url);
        Registry registry = null;
        boolean check = url.getParameter(CHECK_KEY, true) && url.getPort() != 0;

        // 锁定注册表访问过程以确保注册表的单个实例
        registryManager.getRegistryLock().lock();
        try {
            defaultNopRegistry = registryManager.getDefaultNopRegistryIfDestroyed();
            if (null != defaultNopRegistry) {
                return defaultNopRegistry;
            }

            registry = registryManager.getRegistry(key);
            if (registry != null) {
                return registry;
            }

            //创建注册中心通过 spi/ioc
            registry = createRegistry(url);
            if (check && registry == null) {
                throw new IllegalStateException("Can not create registry " + url);
            }

            if (registry != null) {
                registryManager.putRegistry(key, registry);
            }
        } catch (Exception e) {
            if (check) {
                throw new RuntimeException("Can not create registry " + url, e);
            } else {
                // 1-11 无法获取或创建注册表(服务)对象。
                LOGGER.warn(REGISTRY_FAILED_CREATE_INSTANCE, "", "", "Failed to obtain or create registry ", e);
            }
        } finally {
            // 释放锁
            registryManager.getRegistryLock().unlock();
        }

        return registry;
    }

每种注册中心都有自己具体的工厂类,代码中没有显式的判断。主要是判断方法在就在RegistryFactory接口中,该接口里有一个Registry getRegistry(URL url)方法,该方法上有@Adaptive({"protocol"))注解。

java 复制代码
@SPI(scope = APPLICATION)
public interface RegistryFactory {

    /**
     * 配置连接到注册表支持的模式
     */
    @Adaptive({PROTOCOL_KEY})
    Registry getRegistry(URL url);
}

@Adaptive这个注解会自动生成代码实现一些逻辑,它的value参数会从URL中获取protocol键的值,并根据获取的值来调用不同的工厂类。例如,当url.protocol = nacos时,获得NacosRegistryFactory实现类。

dubbo支持的注册中心如下图: 其中各类的作用如下:

  • AbstractRegistry:提供由缓存文件支持的故障保护注册表服务。当注册表中心崩溃时,使用者/提供者仍然可以找到彼此。
  • FailbackRegistry:提供自动重试功能的注册表服务的模板实现。
  • CacheableFailbackRegistry:基于FailbackRegistry,它添加了URLAddress和URLParam缓存以节省RAM空间。
  • ServiceDiscoveryRegistry:ServiceDiscoveryRegistry是一个非常特殊的Registry实现,用于桥接旧的接口级服务发现模型。其中在3.0中以兼容的方式引入了新的服务发现模型。
  • NacosRegistry:Nacos注册中心
  • MulticastRegistry:Multicast 注册中心不需要启动任何中心节点,只要广播地址一样,就可以互相发现。
  • ZookeeperRegistry:zookeeper注册中心

总结

本文深入探讨了Dubbo框架中注册中心组件的设计与实现。介绍了工厂模式的基本概念以及它在设计模式中的角色。通过源码分析,揭示了Dubbo是如何利用工厂模式来管理不同类型的注册中心实例,如ZooKeeper、Nacos等,以及如何通过扩展接口来实现对新注册中心类型的快速支持。

Dubbo注册中心的设计体现了工厂模式的强大之处,为构建灵活、可扩展的分布式系统提供了有力的设计参考。通过继续探索和实践这些设计原则,我们可以进一步提升我们的系统设计能力,以应对不断变化的技术挑战。

相关推荐
子兮曰4 天前
jev-ultrafast 深度解析:7 秒订机票的浏览器 Agent 是如何炼成的
前端·后端·agent
子兮曰4 天前
Jev 爆发一周:7 秒 Agent 背后的 System One 生态与三场争议
前端·后端·ai编程
爱勇宝4 天前
ZCode 开源 24 小时:一份没有历史的账本,回答不了"有没有偷代码"
前端·后端·chatglm (智谱)
胡写代码4 天前
别再前后端各写一套表单校验了
java·后端
大勇前进4 天前
原生 PHP 还是 Laravel?小项目到底要不要上框架
后端
yuzhi_liu4 天前
我用 LangGraph4j 实现 Multi-Agent Supervisor
后端
alsmile4 天前
Node-RED 之外,国产规则引擎的新方案:基于标准语法,Go 先行实现
后端·开源·go
大白804 天前
PHP 内存溢出排查思路:看懂报错日志,精准定位问题
后端
二月龙4 天前
PHP 接口返回统一响应封装,让前后端对接更省心
后端
盖伦发发4 天前
软件工程SOLID 五大设计原则
后端·软件工程