注册中心API模块(dubbo-registry-api)

总体介绍

RegistryFactory

//得到注册中心对象
@SPI("dubbo")
public interface RegistryFactory {

    /**
     * 1. 当设置check=false时表示不检查连接,否则在连接不上时抛出异常。
     *  2. 支持URL上的username:password权限认证。
     *  3. 支持backup=10.20.153.10备选注册中心集群地址。
     *  4. 支持file=registry.cache本地磁盘文件缓存。
     *  5. 支持timeout=1000请求超时设置。
     *  6. 支持session=60000会话超时或过期设置
     */
    @Adaptive({"protocol"}) //根据 url.protocol 获得对应的 RegistryFactory 实现类
    Registry getRegistry(URL url);//例如url.protocol = zookeeper 时,获得 ZookeeperRegistryFactory 实现类。
}
复制代码

AbstractRegistryFactory

RegistryFactory的抽象实现类。实现 Registry 的容器管理。

   // 锁[static] 用于 #destroyAll() 和 #getRegistry(url) 方法,对 REGISTRIES 访问的竞争。
    private static final ReentrantLock LOCK = new ReentrantLock();

    //Registry[static] 集合
    private static final Map<String, Registry> REGISTRIES = new ConcurrentHashMap<String, Registry>();
//子类实现该方法,根据url创建其对应的 Registry 实现类。
//例如,ZookeeperRegistryFactory 的该方法,创建 ZookeeperRegistry 对象。
protected abstract Registry createRegistry(URL url);

  @Override//获得注册中心 Registry 对象。优先从缓存中获取,否则进行创建。
    public Registry getRegistry(URL url) {
        url = url.setPath(RegistryService.class.getName())
                .addParameter(Constants.INTERFACE_KEY, RegistryService.class.getName())
                .removeParameters(Constants.EXPORT_KEY, Constants.REFER_KEY);
        String key = url.toServiceString();
        LOCK.lock();
        try {
            Registry registry = REGISTRIES.get(key);
            if (registry != null) {
                return registry;
            }
            registry = createRegistry(url);
            if (registry == null) {
                throw new IllegalStateException("Can not create registry " + url);
            }
            REGISTRIES.put(key, registry);
            return registry;
        } finally {
            LOCK.unlock();
        }
    }
复制代码

RegistryService

//注册中心服务接口,定义了注册、订阅、查询三种操作方法
  public interface RegistryService {
  //注册数据,比如:提供者地址,消费者地址,路由规则,覆盖规则,等数据。
    void register(URL url);
    //订阅符合条件的已注册数据,当有注册数据变更时自动推送。
    void subscribe(URL url, NotifyListener listener);
     //查询符合条件的已注册数据,与订阅的推模式相对应,这里为拉模式,只返回一次结果。
    List<URL> lookup(URL url);
}
复制代码

Registry

Registry ,注册中心接口。Registry 继承了:
	RegistryService 接口,拥有拥有注册、订阅、查询三种操作方法。
	Node 接口,拥有节点相关的方法。
复制代码

AbstractRegistry

public abstract class AbstractRegistry implements Registry {

    // URL地址分隔符,用于文件缓存中,服务提供者URL分隔
    private static final char URL_SEPARATOR = ' ';
    //  URL地址分隔正则表达式,用于解析文件缓存中服务提供者URL列表
    private static final String URL_SPLIT = "\\s+";
    // Log output
    protected final Logger logger = LoggerFactory.getLogger(getClass());
    //本地磁盘缓存。
    //1. 其中特殊的 key 值 .registies 记录注册中心列表
    //  2. 其它均为 {@link #notified} 服务提供者列表
    private final Properties properties = new Properties();
    // 注册中心缓存写入执行器。线程数=1
    private final ExecutorService registryCacheExecutor = Executors.newFixedThreadPool(1, new NamedThreadFactory("DubboSaveRegistryCache", true));
    //  是否同步保存文件
    private final boolean syncSaveFile;
    //数据版本号
    private final AtomicLong lastCacheChanged = new AtomicLong();
    //已注册 URL 集合。注意,注册的 URL 不仅仅可以是服务提供者的,也可以是服务消费者的
    private final Set<URL> registered = new ConcurrentHashSet<URL>();
    // 订阅 URL 的监听器集合
    //key:消费者的 URL
    private final ConcurrentMap<URL, Set<NotifyListener>> subscribed = new ConcurrentHashMap<URL, Set<NotifyListener>>();
    //被通知的 URL 集合
    //key1:消费者的 URL
    // key2:分类,例如:providers、consumers、routes、configurators。【实际无 consumers ,因为消费者不会去订阅另外的消费者的列表】
    private final ConcurrentMap<URL, Map<String, List<URL>>> notified = new ConcurrentHashMap<URL, Map<String, List<URL>>>();
    private URL registryUrl;//注册中心 URL
    // 本地磁盘缓存文件,缓存注册中心的数据
    private File file;

    public AbstractRegistry(URL url) {
        setUrl(url);
        // Start file save timer
        syncSaveFile = url.getParameter(Constants.REGISTRY_FILESAVE_SYNC_KEY, false);
        String filename = url.getParameter(Constants.FILE_KEY, System.getProperty("user.home") + "/.dubbo/dubbo-registry-" + url.getParameter(Constants.APPLICATION_KEY) + "-" + url.getAddress() + ".cache");
        File file = null;
        if (ConfigUtils.isNotEmpty(filename)) {
            file = new File(filename);
            if (!file.exists() && file.getParentFile() != null && !file.getParentFile().exists()) {
                if (!file.getParentFile().mkdirs()) {
                    throw new IllegalArgumentException("Invalid registry store file " + file + ", cause: Failed to create directory " + file.getParentFile() + "!");
                }
            }
        }
        this.file = file;
        loadProperties();// 加载本地磁盘缓存文件到内存缓存
        notify(url.getBackupUrls());// 通知监听器,URL 变化结果
    }
复制代码

FailbackRegistry

/**
 * 支持失败重试的 Registry 抽象类。
 * AbstractRegistry 进行的注册、订阅等操作,更多的是修改状态,而无和注册中心实际的操作。
 * FailbackRegistry 在 AbstractRegistry 的基础上,实现了和注册中心实际的操作,并且支持失败重试的特性。
 *
 */
public abstract class FailbackRegistry extends AbstractRegistry {
        // failedXXX 属性 每种操作都有一个记录失败的集合。

    // 定时任务执行器
    private final ScheduledExecutorService retryExecutor = Executors.newScheduledThreadPool(1, new NamedThreadFactory("DubboRegistryFailedRetryTimer", true));

    // 失败重试定时器,定时检查是否有请求失败,如有,无限次重试
    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);
        // 重试频率,单位:毫秒
        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);
    }
复制代码

NotifyListener

public interface NotifyListener {

    /**
     * 当收到服务变更通知时触发
     * 1. 总是以服务接口和数据类型为维度全量通知,即不会通知一个服务的同类型的部分数据,用户不需要对比上一次通知结果。
     *  2. 订阅时的第一次通知,必须是一个服务的所有类型数据的全量通知。
     *  3. 中途变更时,允许不同类型的数据分开通知,比如:providers, consumers, routers, overrides,允许只通知其中一种类型,但该类型的数据必须是全量的,不是增量的。
     *   4. 如果一种类型的数据为空,需通知一个empty协议并带category参数的标识性URL数据
     *   5. 通知者(即注册中心实现)需保证通知的顺序,比如:单线程推送,队列串行化,带版本对比
     */
    void notify(List<URL> urls);//urls 已注册信息列表,总不为空

}
复制代码

转载于:https://juejin.im/post/5be8304ee51d450f9c6cfd29

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值