DyamicServerListLoadBalancer的构造方法中,当接收到的参数为IClientConfig的时候,会直接调用initWithNiwsConfig()方法开始根据配置类开始进行初始化。

首先会调用父类BaseLoaderBalancer的initWithNiwsConfig()方法。

在BaseLoaderBalancer这里首先会在配置类中寻找相应的IPing和IRule并获取这两个类相应的实例,而后在initWithConfig()方法中对这两者以及相关属性进行更详细的配置。

void initWithConfig(IClientConfig clientConfig, IRule rule, IPing ping) {this.config = clientConfig;String clientName = clientConfig.getClientName();this.name = clientName;int pingIntervalTime = Integer.parseInt(""+ clientConfig.getProperty(CommonClientConfigKey.NFLoadBalancerPingInterval,Integer.parseInt("30")));int maxTotalPingTime = Integer.parseInt(""+ clientConfig.getProperty(CommonClientConfigKey.NFLoadBalancerMaxTotalPingTime,Integer.parseInt("2")));setPingInterval(pingIntervalTime);setMaxTotalPingTime(maxTotalPingTime);// cross associate with each other// i.e. Rule,Ping meet your container LB// LB, these are your Ping and Rule guys ...setRule(rule);setPing(ping);setLoadBalancerStats(new LoadBalancerStats(clientName));rule.setLoadBalancer(this);if (ping instanceof AbstractLoadBalancerPing) {((AbstractLoadBalancerPing) ping).setLoadBalancer(this);}logger.info("Client:" + name + " instantiated a LoadBalancer:"+ toString());boolean enablePrimeConnections = clientConfig.get(CommonClientConfigKey.EnablePrimeConnections, DefaultClientConfigImpl.DEFAULT_ENABLE_PRIME_CONNECTIONS);if (enablePrimeConnections) {this.setEnablePrimingConnections(true);PrimeConnections primeConnections = new PrimeConnections(this.getName(), clientConfig);this.setPrimeConnections(primeConnections);}init();}

先在配置类中读取ping操作的间隔,默认30秒。然后在setPingInterval()方法中将这一参数正式用到。在setPingInterval()方法中,会调用setupPingTask()方法正式根据时间间隔创建定时任务PingTask来不断间隔一定时间去对所有地址进行ping检查。

private void setupPingTask() {if (canSkipPing()) {return;}if (lbTimer != null) {lbTimer.cancel();}lbTimer = new ShutdownEnabledTimer("NFLoadBalancer-PingTimer-" + name,true);lbTimer.schedule(new PingTask(), 0, pingIntervalSeconds * 1000);forceQuickPing();
}class PingTask extends TimerTask {public void run() {Pinger ping = new Pinger();try {ping.runPinger();} catch (Throwable t) {logger.error("Throwable caught while running extends for "+ name, t);}}
}public void runPinger() {if (pingInProgress.get()) {return; // Ping in progress - nothing to do} else {pingInProgress.set(true);}// we are "in" - we get to PingObject[] allServers = null;boolean[] results = null;Lock allLock = null;Lock upLock = null;try {/** The readLock should be free unless an addServer operation is* going on...*/allLock = allServerLock.readLock();allLock.lock();allServers = allServerList.toArray();allLock.unlock();int numCandidates = allServers.length;results = new boolean[numCandidates];if (logger.isDebugEnabled()) {logger.debug("LoadBalancer:  PingTask executing ["+ numCandidates + "] servers configured");}for (int i = 0; i < numCandidates; i++) {results[i] = false; /* Default answer is DEAD. */try {// NOTE: IFF we were doing a real ping// assuming we had a large set of servers (say 15)// the logic below will run them serially// hence taking 15 times the amount of time it takes// to ping each server// A better method would be to put this in an executor// pool// But, at the time of this writing, we dont REALLY// use a Real Ping (its mostly in memory eureka call)// hence we can afford to simplify this design and run// this// seriallyif (ping != null) {results[i] = ping.isAlive((Server) allServers[i]);}} catch (Throwable t) {logger.error("Exception while pinging Server:"+ allServers[i], t);}}final List<Server> newUpList = new ArrayList<Server>();final List<Server> changedServers = new ArrayList<Server>();for (int i = 0; i < numCandidates; i++) {boolean isAlive = results[i];Server svr = (Server) allServers[i];boolean oldIsAlive = svr.isAlive();svr.setAlive(isAlive);if (oldIsAlive != isAlive) {changedServers.add(svr);if (logger.isDebugEnabled()) {logger.debug("LoadBalancer:  Server [" + svr.getId()+ "] status changed to "+ (isAlive ? "ALIVE" : "DEAD"));}}if (isAlive) {newUpList.add(svr);}}// System.out.println(count + " servers alive");upLock = upServerLock.writeLock();upLock.lock();upServerList = newUpList;upLock.unlock();notifyServerStatusChangeListener(changedServers);} catch (Throwable t) {logger.error("Throwable caught while running the Pinger-"+ name, t);} finally {pingInProgress.set(false);}
}

在ping检查中,最后调用到的是Pinger的runPinger()方法。

为了保证这一操作的线程安全,通过信号量的形式保证这一操作在某一时间的唯一性。

而后会获取所有当前所有的服务器数组,遍历数组去依次进行ping确认其状态是否可用,如果新的状态与之前的状态发生改变,那么就将其存入存放状态发生改变的服务器数组,并且如果其状态为可用,则加入可用服务器数组并更新。

而后通知所有状态改变监听器公告所有发生状态改变的服务器。

如果采用了PingUrl会直接构造url对相应的服务器进行请求来判断该服务器是否可用。

该任务的定时调用间隔时间就是配置的ping间隔时间。

之后回到DyamicServerListLoadBalancer的initWithNiwConfig()方法,会配置服务器列表和服务器过滤器。

而后调用restOfInit()方法,并在其中调用updateListOfServers()方法更新服务器列表。

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);}}lastUpdated.set(System.currentTimeMillis());updateAllServerList(servers);
}

这里会根据之前得到的服务器列表类来获取服务器列表。

如果是默认的ConfigurationBasedServerList,则会直接读配置类中的服务器列表并返回。

而如果采用了DiscoveryEnabledNIWSServerList,则向eureka-client获得相应的服务器列表。

Ribbon的初始化源码相关推荐

  1. Quartz的Scheduler初始化源码分析

    2019独角兽企业重金招聘Python工程师标准>>> Quartz的使用:http://donald-draper.iteye.com/blog/2321886  Quartz的S ...

  2. 【SemiDrive源码分析】【X9芯片启动流程】12 - freertos_safetyos目录Cortex-R5 DIL2.bin 之 sdm_display_init 显示初始化源码分析

    [SemiDrive源码分析][X9芯片启动流程]12 - freertos_safetyos目录Cortex-R5 DIL2.bin 之 sdm_display_init 显示初始化源码分析 一.s ...

  3. SpringMVC源码探究软件六合网站制作(一)----初始化源码

    随着软件 , 开发技术的持续发展,框架技术层出不穷.还是那句话,任何框架技术都是对基础技术的封装.所以,真正要学好用好一个框架,研究其源码都是最直接最有效的途径. 随着Spring技术体系的强势发展, ...

  4. Spring IoC容器初始化源码(1)—容器初始化入口以及setConfigLocations设置容器配置信息【一万字】

      基于最新Spring 5.x,对于基于XML的Spring IoC容器初始化过程中的setConfigLocations设置容器配置信息方法的源码进行了详细分析,最后给出了比较详细的方法调用时序图 ...

  5. spring初始化源码浅析之代码浅析

    目录 1.refresh()简介 2.关键代码跟踪 ​2.1.obtainFreshBeanFactory()代码分析 2.2.invokeBeanFactoryPostProcessors(bean ...

  6. spring4.1.8初始化源码学习三部曲之三:AbstractApplicationContext.refresh方法

    本章是<spring4.1.8初始化源码学习三部曲>系列的终篇,重点是学习AbstractApplicationContext类的refresh()方法: 原文地址:https://blo ...

  7. Solr初始化源码分析-Solr初始化与启动

    用solr做项目已经有一年有余,但都是使用层面,只是利用solr现有机制,修改参数,然后监控调优,从没有对solr进行源码级别的研究.但是,最近手头的一个项目,让我感觉必须把solrn内部原理和扩展机 ...

  8. 千层套路 - Vue 3.0 初始化源码探秘

    关注若川视野, 回复"pdf" 领取资料,回复"1",可加群长期交流学习 刘崇桢,微医云服务团队前端工程师,左手抱娃.右手持家的非典型码农. 9 月初 Vue. ...

  9. Spring 事务初始化源码分析

    前言 在上篇文章 Spring 事务使用详解 中详细介绍了 Spring 事务的使用过程,今天就来看下 Spring 事务是如何来实现,比如 Spring 事务在初始化的时候做了什么,Spring 事 ...

最新文章

  1. 十五天精通WCF——第六天 你必须要了解的3种通信模式
  2. DBA入门之路:由浅入深的总结学习法
  3. 【怎样写代码】偷窥高手 -- 反射技术(一):前期准备
  4. 记一次企业级爬虫系统升级改造(一)
  5. js var是什么类型_JS变量的执行环境和生命周期
  6. Spring Hibernate集成示例教程
  7. 8个超好用的Python内置函数,提升效率必备
  8. 复杂类型java对象 — dto数据传输对象
  9. python 颜色空间转换_python opencv入门 颜色空间转换(9)
  10. Linux OPENSSL的简单用法
  11. Linux下进程/程序网络带宽占用情况查看工具 -- NetHogs
  12. MySQL 新增、修改、删除 字段 sql语句
  13. python自制一款职位分析器,一键生成岗位分析报告
  14. The chain rule(链式法则)
  15. [易飞]一张领料单单身仓库飞了引起的思考
  16. php Guzzle源码,PHP Guzzle获取请求
  17. Microsoft SUS Deployment
  18. 【数据可视化】bar函数绘制简单柱状图
  19. Nim游戏入门+SG函数
  20. 同步已有数据库到Django框架报错

热门文章

  1. 诗与远方:无题(六十三)- 杂诗,然,矣
  2. 诗与远方:无题(三十七)- 凿壁偷光
  3. 从高中生活步入大学生活
  4. MyBatis 接口绑定方案及多参数传递、动态 SQL、ThreadLocal、缓存
  5. Notepad++插件Base64编解码
  6. vue导出Excel(二)
  7. antv图例出现分页_图例-自定义文本样式
  8. C++文件操作(打开、关闭、文件读取数据存入数组)
  9. 彻底理解被称为二叉树神级遍历的莫里斯(Morris)算法
  10. 重载(Overload)和重写(Overide)