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

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

工厂模式的介绍

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

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

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

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

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

UML模型图如下:
在这里插入图片描述

dubbo源码中的应用

所有的注册中心实现,都是通过对应的工厂创建的。工厂类之间的关系如图:
在这里插入图片描述

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

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/iocregistry = 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”))注解。

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

相关文章:

  • Vista 2.08: The storm chaser
  • Linux下彻底卸载MySQL数据库
  • 2.21 Qt day2 菜单栏/工具栏/状态栏/浮动窗口、UI界面、信号与槽
  • [设计模式Java实现附plantuml源码~行为型]协调多个对象之间的交互——中介者模式
  • 标题:从预编译到链接:探索C/C++程序的翻译环境全貌
  • [C#]winform使用引导APSF和梯度自适应卷积增强夜间雾图像的可见性算法实现夜间雾霾图像的可见度增强
  • PotPlayer+Alist挂载并播放网盘视频
  • mplfinance 使用make_addplot做复杂股票走势图
  • dell r740服务器黄灯闪烁维修现场解决
  • 167基于matlab的根据《液体动静压轴承》编写的有回油槽径向静压轴承的程序
  • vant-search确定按钮变成了“换行”文字
  • 05.STLvector、list、stack、queue
  • (done) 两个矩阵 “相似” 是什么意思?
  • 多维时序 | Matlab实现基于VMD-DBO-LSTM、VMD-LSTM、LSTM的多变量时间序列预测
  • Rust ?运算符 Rust读写txt文件
  • 【5+】跨webview多页面 触发事件(二)
  • Angular2开发踩坑系列-生产环境编译
  • flask接收请求并推入栈
  • gops —— Go 程序诊断分析工具
  • Java,console输出实时的转向GUI textbox
  • JavaScript的使用你知道几种?(上)
  • node-sass 安装卡在 node scripts/install.js 解决办法
  • PHP变量
  • Python代码面试必读 - Data Structures and Algorithms in Python
  • scala基础语法(二)
  • spring学习第二天
  • webpack入门学习手记(二)
  • 对JS继承的一点思考
  • 高度不固定时垂直居中
  • 记一次用 NodeJs 实现模拟登录的思路
  • 讲清楚之javascript作用域
  • 排序算法之--选择排序
  • 前端之Sass/Scss实战笔记
  • 如何打造100亿SDK累计覆盖量的大数据系统
  • 腾讯视频格式如何转换成mp4 将下载的qlv文件转换成mp4的方法
  • 我是如何设计 Upload 上传组件的
  • 回归生活:清理微信公众号
  • !!【OpenCV学习】计算两幅图像的重叠区域
  • #我与虚拟机的故事#连载20:周志明虚拟机第 3 版:到底值不值得买?
  • $ git push -u origin master 推送到远程库出错
  • $.type 怎么精确判断对象类型的 --(源码学习2)
  • $emit传递多个参数_PPC和MIPS指令集下二进制代码中函数参数个数的识别方法
  • (Git) gitignore基础使用
  • (NO.00004)iOS实现打砖块游戏(十二):伸缩自如,我是如意金箍棒(上)!
  • (二)斐波那契Fabonacci函数
  • (二十一)devops持续集成开发——使用jenkins的Docker Pipeline插件完成docker项目的pipeline流水线发布
  • (附源码)spring boot车辆管理系统 毕业设计 031034
  • (附源码)springboot 智能停车场系统 毕业设计065415
  • (教学思路 C#之类三)方法参数类型(ref、out、parmas)
  • (企业 / 公司项目)前端使用pingyin-pro将汉字转成拼音
  • .360、.halo勒索病毒的最新威胁:如何恢复您的数据?
  • .NET CF命令行调试器MDbg入门(四) Attaching to Processes
  • .NET Standard / dotnet-core / net472 —— .NET 究竟应该如何大小写?
  • .NET 读取 JSON格式的数据
  • .net 前台table如何加一列下拉框_如何用Word编辑参考文献