在上文中介绍了基础类AbstractRegistry类的解释,在本篇中将继续介绍该包下的其他类。

FailbackRegistry

该类继承了AbstractRegistry,AbstractRegistry中的注册订阅等方法,实际上就是一些内存缓存的变化,而真正的注册订阅的实现逻辑在FailbackRegistry实现,并且FailbackRegistry提供了失败重试的机制。

初始化

// Scheduled executor service
// 定时任务执行器
private final ScheduledExecutorService retryExecutor = Executors.newScheduledThreadPool(1, new NamedThreadFactory("DubboRegistryFailedRetryTimer", true)); // Timer for failure retry, regular check if there is a request for failure, and if there is, an unlimited retry
// 失败重试定时器,定时去检查是否有请求失败的,如有,无限次重试。
private final ScheduledFuture<?> retryFuture; // 注册失败的URL集合
private final Set<URL> failedRegistered = new ConcurrentHashSet<URL>(); // 取消注册失败的URL集合
private final Set<URL> failedUnregistered = new ConcurrentHashSet<URL>(); // 订阅失败的监听器集合
private final ConcurrentMap<URL, Set<NotifyListener>> failedSubscribed = new ConcurrentHashMap<URL, Set<NotifyListener>>(); // 取消订阅失败的监听器集合
private final ConcurrentMap<URL, Set<NotifyListener>> failedUnsubscribed = new ConcurrentHashMap<URL, Set<NotifyListener>>(); // 通知失败的URL集合
private final ConcurrentMap<URL, Map<NotifyListener, List<URL>>> failedNotified = new ConcurrentHashMap<URL, Map<NotifyListener, List<URL>>>(); /**
* The time in milliseconds the retryExecutor will wait
*/
// 重试频率
private final int retryPeriod;

构造函数

public FailbackRegistry(URL url) {
super(url);
// 从url中读取重试频率,如果为空,则默认5000ms
this.retryPeriod = url.getParameter(Constants.REGISTRY_RETRY_PERIOD_KEY, Constants.DEFAULT_REGISTRY_RETRY_PERIOD);
// 创建失败重试定时器
this.retryFuture = retryExecutor.scheduleWithFixedDelay(new Runnable() {
@Override
public void run() {
// Check and connect to the registry
try {
//重试
retry();
} catch (Throwable t) { // Defensive fault tolerance
logger.error("Unexpected error occur at failed retry, cause: " + t.getMessage(), t);
}
}
}, retryPeriod, retryPeriod, TimeUnit.MILLISECONDS);
}

构造函数主要是创建了失败重试的定时器,重试频率从URL取,如果没有设置,则默认为5000ms。

在该类中对注册、取消注册、订阅、取消订阅进行了重写操作,代码逻辑相对简单。

 @Override
public void register(URL url) {
super.register(url);
//首先从失败的缓存中删除该url
failedRegistered.remove(url);
failedUnregistered.remove(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)
&& !Constants.CONSUMER_PROTOCOL.equals(url.getProtocol());
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("Failed to register " + url + ", waiting for retry, cause: " + t.getMessage(), t);
} // Record a failed registration request to a failed list, retry regularly
// 把这个注册失败的url放入缓存,并且定时重试。
failedRegistered.add(url);
}
}

在注册中它会失败的注册缓存和失败的未注册缓存集合中移除该URL,然后向注册中心执行注册。

AbstractRegistryFactory

该类实现了RegistryFactory接口,抽象了createRegistry方法,它实现了Registry的容器。

初始化

 private static final ReentrantLock LOCK = new ReentrantLock();

    // Registry Collection Map<RegistryAddress, Registry>
// Registry 集合
private static final Map<String, Registry> REGISTRIES = new ConcurrentHashMap<String, Registry>();

销毁所有的Registry对象,并清理缓存数据

public static Collection<Registry> getRegistries() {
return Collections.unmodifiableCollection(REGISTRIES.values());
} public static void destroyAll() {
if (LOGGER.isInfoEnabled()) {
LOGGER.info("Close all registries " + getRegistries());
}
// Lock up the registry shutdown process
// 获得锁
LOCK.lock();
try {
for (Registry registry : getRegistries()) {
try {
// 销毁
registry.destroy();
} catch (Throwable e) {
LOGGER.error(e.getMessage(), e);
}
}
// 清空缓存
REGISTRIES.clear();
} finally {
// Release the lock
// 释放锁
LOCK.unlock();
}
}

该方法是实现了Registry接口的方法,这里最要注意的是createRegistry,因为AbstractRegistryFfactory本身就是抽象类,而createRegistry也是抽象方法,为了让子类只要关注该方法,比如说redis实现的注册中心和zookeeper实现的注册中心创建方式肯定不同,而他们相同的一些操作都已经在AbstractRegistryFactory中实现,所以只要关注且实现该抽象方法即可。

@Override
public Registry getRegistry(URL url) {
// 修改url
url = url.setPath(RegistryService.class.getName())
.addParameter(Constants.INTERFACE_KEY, RegistryService.class.getName())
.removeParameters(Constants.EXPORT_KEY, Constants.REFER_KEY);
// 计算key值
String key = url.toServiceString();
// Lock the registry access process to ensure a single instance of the registry
// 获得锁
LOCK.lock();
try {
Registry registry = REGISTRIES.get(key);
if (registry != null) {
return registry;
}
// 创建Registry对象
registry = createRegistry(url);
if (registry == null) {
throw new IllegalStateException("Can not create registry " + url);
}
// 添加到缓存。
REGISTRIES.put(key, registry);
return registry;
} finally {
// Release the lock
// 释放锁
LOCK.unlock();
}
}

Dubbo-服务注册中心之AbstractRegistryFactory等源码的更多相关文章

  1. [源码阅读] 阿里SOFA服务注册中心MetaServer(1)

    [源码阅读] 阿里SOFA服务注册中心MetaServer(1) 目录 [源码阅读] 阿里SOFA服务注册中心MetaServer(1) 0x00 摘要 0x01 服务注册中心 1.1 服务注册中心简 ...

  2. [源码阅读] 阿里SOFA服务注册中心MetaServer(2)

    [源码阅读] 阿里SOFA服务注册中心MetaServer(2) 目录 [源码阅读] 阿里SOFA服务注册中心MetaServer(2) 0x00 摘要 0x01 MetaServer 注册 1.1 ...

  3. [源码阅读] 阿里SOFA服务注册中心MetaServer(3)

    [源码阅读] 阿里SOFA服务注册中心MetaServer(3) 目录 [源码阅读] 阿里SOFA服务注册中心MetaServer(3) 0x00 摘要 0x01 概念 1.1 分布式一致性 1.2 ...

  4. 搭建高可用服务注册中心-Spring Cloud学习第一天(非原创)

    文章大纲 一.Spring Cloud基础知识介绍二.创建单一的服务注册中心三.创建一个服务提供者四.搭建高可用服务注册中心五.项目源码与参考资料下载六.参考文章   一.Spring Cloud基础 ...

  5. 基于ZooKeeper的服务注册中心

    本文介绍基于ZooKeeper的Dubbo服务注册中心的原理. 1.ZooKeeper中的节点 ZooKeeper是一个树形结构的目录服务,支持变更推送,因此非常适合作为Dubbo服务的注册中心. 注 ...

  6. SpringCloud-服务注册与实现-Eureka创建服务注册中心(附源码下载)

    场景 SpringCloud学习之运行第一个Eureka程序: https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/90611451 S ...

  7. Dubbo多注册中心和Zookeeper服务的迁移

    一.Dubbo多注册中心 1. 应用场景 例如阿里有些服务来不及在青岛部署,只在杭州部署,而青岛的其它应用需要引用此服务,就可以将服务同时注册到两个注册中心. consumer.xml <?xm ...

  8. 阿里dubbo服务注册原理解析

           阿里分布式服务框架 dubbo现在已成为了外面很多中小型甚至一些大型互联网公司作为服务治理的一个首选或者考虑方案,相信大家在日常工作中或多或少都已经用过或者接触过dubbo了.但是我搜了 ...

  9. SpringCloud学习(3)——Eureka服务注册中心及服务发现

    Eureka概述: Eureka是Netflix的一个子模块, 也是核心模块之一.Eureka是一个基于REST的服务, 用于定位服务, 以实现云端中间层服务发现和故障转移.服务注册与发现对于微服务框 ...

随机推荐

  1. Keepalived 工作原理和配置说明

    keepalived是什么: 简单来说 Keepalived 的功能功能1.使用VRRP协议 来控制一组高可用(HA) 主备系统,一台master工作,一台slave热备:master失效后slave ...

  2. chromedriver和firefox driver的安装过程

    环境:ubuntu14.04, python2.7 selenium2.0 文章参考出处:http://blog.csdn.net/heybob/article/details/52922645 ch ...

  3. TCP协议可靠性是如何保证之滑动窗口,超时重发,序列号确认应答信号

    原创文章首发于公众号:「码农富哥」,欢迎收藏和关注,如转载请注明出处! TCP 是一种提供可靠性交付的协议. 也就是说,通过 TCP 连接传输的数据,无差错.不丢失.不重复.并且按序到达. 但是在网络 ...

  4. 教你快速使用数据可视化BI软件创建4S店销售数据大屏

    灯果数据可视化BI软件是新一代人工智能数据可视化大屏软件,内置丰富的大屏模板,可视化编辑操作,无需任何经验就可以创建属于你自己的大屏.大家可以在他们的官网下载软件.   本文以4S店销售数据大屏为例为 ...

  5. 教你用python爬虫监控教务系统,查成绩快人一步!

    教你用python爬虫监控教务系统,查成绩快人一步!这几天考了大大小小几门课,教务系统又没有成绩通知功能,为了急切想知道自己挂了多少门,于是我写下这个脚本. 设计思路:设计思路很简单,首先对已有的成绩 ...

  6. 网页DIV+CSS布局与ifame传统布局对比

    通常我们从设计师手上拿到设计稿,按照功能划分为很多小块,然后再利用div+css写成静态页面按照设计稿排列还原,最后把具体内容填充到小块里面.网页布局就是你想要的页面功能在你拿到设计图切块完成重新排列 ...

  7. M5310-A 版本

         模块外表            型号                           BAND                          M5310-A MBRH0S04 +NB ...

  8. CSS字体连写及外观属性

    一.font:字体连写 使用font属性时,必须按以下语法格式中的顺序书写,不能更换顺序,各个属性以空格隔开.注意:其中不需要设置的属性可以省略(取默认值),但必须保留font-size和font-f ...

  9. CentOS7安装Python3.6.8

    1.首先通过yum安装python可能用到的依赖 yum install openssl-devel bzip2-devel expat-devel gdbm-devel readline-devel ...

  10. SecureCRT 按退格键出现 ^H 的解决办法  

    问题如图 打开SecureCRT 界面,最上方工具栏 1.选项→会话选项 2.终端→仿真→映射键 3.其他选项→勾选 Backspace 发送 delete(B) 4.点击确定即可 另外在不可编辑状态 ...