• Dubbo-服务注册中心之AbstractRegistryFactory等源码


    在上文中介绍了基础类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();
            }
        }
    
  • 相关阅读:
    tensorflow中的name_scope, variable_scope
    tf.data.Dataset类的用法
    tensorflow错误:Shape (10, ?) must have rank at least 3
    最大似然估计、最大后验估计、贝叶斯估计的对比
    自然语言处理简述
    深度学习之GRU网络
    深度学习之Batch Normalization
    自然语言处理之序列标注问题
    Ubuntu安装jdk
    TypeScript 高级类型
  • 原文地址:https://www.cnblogs.com/maratong/p/12333730.html
Copyright © 2020-2023  润新知