Ribbon源码分析--ServerList从哪来(2)

109 阅读2分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第5天,点击查看活动详情

前言

之前过了一遍Ribbon的执行流程,发现ribbon自己会维护一套注册表信息,在IRule实现类中计算服务地址的时候有一个List,而这个List是从ILoadBalancer中获取到的,那么ILoadBalance中的List又从哪里来的?(这里是集成了eureka)

DiscoveryEnabledNIWSServerList

找到ILoadBalancer这个接口后,里面找到一个addServers的接口,顺着这个接口向下找,但是发现好像并没有什么用,然后顺势查找一下ILoadBalancer的几个实现类的构造方法,发现在DynamicServerListLoadBalancer的构造方法中有serverList的变量和restOfInit的方法。但看这个方法的名字就知道是在初始化某些东西

public DynamicServerListLoadBalancer(IClientConfig clientConfig, IRule rule, IPing ping,
                                         ServerList<T> serverList, ServerListFilter<T> filter,
                                         ServerListUpdater serverListUpdater) {
        super(clientConfig, rule, ping);
        this.serverListImpl = serverList;
        this.filter = filter;
        this.serverListUpdater = serverListUpdater;
        if (filter instanceof AbstractServerListFilter) {
            ((AbstractServerListFilter) filter).setLoadBalancerStats(getLoadBalancerStats());
        }
        restOfInit(clientConfig);
    }

继续看restOfInit方法

 void restOfInit(IClientConfig clientConfig) {
        boolean primeConnection = this.isEnablePrimingConnections();
        // turn this off to avoid duplicated asynchronous priming done in BaseLoadBalancer.setServerList()
        this.setEnablePrimingConnections(false);
        enableAndInitLearnNewServersFeature();

        updateListOfServers();
        if (primeConnection && this.getPrimeConnections() != null) {
            this.getPrimeConnections()
                    .primeConnections(getReachableServers());
        }
        this.setEnablePrimingConnections(primeConnection);
        LOGGER.info("DynamicServerListLoadBalancer for client {} initialized: {}", clientConfig.getClientName(), this.toString());
    }

在这里有一个updateListOfServers的方法,看上去就像是更新serverList

 public void updateListOfServers() {
        List<T> servers = new ArrayList<T>();
        if (serverListImpl != null) {
            servers = serverListImpl.getUpdatedListOfServers();
            LOGGER.debug("List of Servers for {} obtained from Discovery client: {}",
                    getIdentifier(), servers);

            if (filter != null) {
                servers = filter.getFilteredListOfServers(servers);
                LOGGER.debug("Filtered List of Servers for {} obtained from Discovery client: {}",
                        getIdentifier(), servers);
            }
        }
        updateAllServerList(servers);
    }

而serverListImpl.getUpdatedListOfServers()这个放个最终会调用到DiscoveryEnabledNIWSServerList.obtainServersViaDiscovery()方法

这个方法就会从eureka client端读取注册表返回,具体怎么拼装数据不需要深入查看。

看到这里感觉从restOfInit的初始化方法调用了一个名字中update的方法,那会不会,第一次调用和后续初始化均在一个方法中呢,反查了一下updateListOfServers()方法,发现在DynamicServerListLoadBalancer类中有一行调用

protected final ServerListUpdater.UpdateAction updateAction = new ServerListUpdater.UpdateAction() {
        @Override
        public void doUpdate() {
            updateListOfServers();
        }
    };

这段代码实际上就是启动了一个后台线程,默认没30s执行一次,调用updateListOfServers()方法,那么初始化注册表流程和更新注册表流程在底层代码实现是一套东西。

总结

第一次初始化的流程

image.png

后续更新流程

image.png