Ribbon 感谢诸葛老师分享
Ribbon调用流程总图
图1
@LoadBalanced这个注解加到RetstTemplate中。
图2
真正调用的话通过restTemplate ,通过服务名称把他解析成对应的ip,他一定是吧这个服务名对应的eureka 所有的ip拿过来,根据负载均衡 挑一个ip出来替换这个名称,最终才去执行httpclient ,调用对应示例的端口。简单的来说Ribbon的通过拦截器,拦截,替换url的过程。
图3
先从loadBalanced开始
图4
57到66行 restTemplates ;spring会把所有加了@LoadBalanced注解的 restTemplate 放到这个restTemplates中,遍历每一个restTemplates , 依次定制(就是把拦截器放到restTemplate中)。
restTemplate的定制器,把拦截器加到restTemplate中。换句话说restTemplate在调用接口时,因为我们新增了拦截器,他会先执行这个拦截器的。我们可以通过这个拦截器去做一些事情。
图5
最关键的是ladBanlancer , 这个是LoadBalancerClient 。这个是一个接口,那么他的实现类是那个呢, 图7
拦截器 ;53行 request.getURI() ,URI 其实就是 http://MICROSERVICE-PROVIDER-USER/ ,getHost 是MICROSERVICE-PROVIDER-USER
图6
图7
loadBalancerClient 的实现类是RibbonLoadBalancerClient ,问题又来了,loadBalancer什么时候初始化的呢,图8
86行 获取负载均衡器,图10 ,通过负载均衡器拿到一个server 。图12
图8
spring boot 在启动的时候回加载RibbonLoadBalancerClient 类。
图9
通过@AutoConfigureAfter 这个注解我们知道,Ribbon依赖于EurekaClientAutoConfguration ,只有这个加载完之后才调用这个。在@AutoConfigureBefore LoadBalancerAutoConfiureation 在这个类之前。那意思是,RibbonLoadBalancerClient 类初始化后,放入容器,
LoadBalancerAutoConfiureation 这个类就可以 @Autower 注入后使用了。
RibbonLoadBalancerClient 类初始化了,然后放入到容器中。
图10
从一个spring工厂中拿到一个ILoadBalancer 是一个接口的类,那这个类是在什么时候示例化的呢,图11
图11
初始化后是ZoneAwareLoadBalancer类
图11-0
super 调用父类 图11-1
图11-1
super调用父类 。 95行restOfInit() 方法。
图11-2
图11-3
142行定时更新eureka示例列表。
图11-4
更新server列表。 240行图11-5
图11-5
获取所有的servers;
图12
图13
availableZones 这个没有设置,所以小等于1 走113行代码
图14
图15
通过负载均衡加载器拿到所有的服务,取其中的一个返回。图 16
图16
取出所有的可用的server. nextIndex 默认值为0 。 假设可用的服务器为2个, nextIndex .getAndIncrement() 先获取,下次加1,那么这次是0 ,也就是 0%2 = 0 ;那么就是eligible.get(0),获取的是第一个。第二次是nextIndex .getAndIncrement() 获取的是1 ,下次是2,那么1%2=1 那么就是eligible.get(1)获取的第一个, 第三次nextIndex .getAndIncrement() 获取的是2 ,下次是3 那么 2%2=0 获取的就是第0个。这就是传说的轮询。