Ribbon和RestTemplate紧密的结合在一起,因此想分析Ribbon,必须要先分析RestTemplate。
一、ClientHttpRequest
RestTemplate在执行的时候需要封装request请求,这个请求谁都可以自定义,他的顶级接口是ClientHttpRequest
本次的主角是InterceptingClientHttpRequest
。改request里面有一个拦截器列表interceptors
。
if (this.iterator.hasNext()) {
ClientHttpRequestInterceptor nextInterceptor = this.iterator.next();
return nextInterceptor.intercept(request, body, this);
}
这里谁都可以自定义拦截器,spring cloud报里面用的是LoadBalancerInterceptor
二、LoadBalancerInterceptor
该拦截器会持有一个LoadBalancerClient
,拦截器主要委托改LoadBalancerClient
去做事。该client也是个接口,他的实现类是RibbonLoadBalancerClient
,这里可以看出其实ribbon就是利用RestTemplate的拦截器来实现的
三、RibbonLoadBalancerClient
这里就是ribbon的核心了,它主要做了三件事情
- 获取接口
ILoadBalancer
的实现类,饶了多少圈,终于见到正主 - 根据负载均衡策略选择某个服务
- 执行真正的请求
3.1 ILoadBalancer
Ribbon用的实现类是ZoneAwareLoadBalancer
ZoneAwareLoadBalancer获取LoadBalancer还是比较特殊的,他是通过SpringClientFactory
来生产的,SpringClientFacotry是ribbon包下面引入的一个新的类,他持有spring的最顶层的ApplicationContext,而且他会新建一个新的子context,这个字contxt创建bean的行为也是和父context一模一样。他的目的其实就是想隔离,每一类bean都有自己的专属context。他创建bean是利用getBean(ILoadBalancer.class)
很好理解。
定时更新服务列表
在ZoneAwareLoadBalancer
中有个初始化方法restOfInit
里面会开启一个定时任务,每30S执行一次updateListOfServers(),这个就是获取服务端readOnly一级缓存里面的注册表信息
3.2 IRule
这个就是根据负载均衡策略选择某个服务。找到rule的具体实现类(默认是随机策略),然后根据策略找到server
public Server chooseServer(Object key) {
if (counter == null) {
counter = createCounter();
}
counter.increment();
if (rule == null) {
return null;
} else {
try {
return rule.choose(key);
} catch (Exception e) {
logger.warn("LoadBalancer [{}]: Error choosing server for key {}", name, key, e);
return null;
}
}
}
3.3 执行真正的请求
上一步已经获得了真正的server,里面包好了真正的ip和端口,这一步就是走普通的http调用即可
四、拦截器的配置
可见ribbon就是靠RestTemplate的拦截器来完成自定义代码的植入,所以肯定有配置是关于这方面的,但是我分析下来感觉比较冗余,我只花了一个图,不想继续分析了
来自配置类LoadBalancerAutoConfiguration