ribbon 实现客户端的负载均衡
实现方式如下所示
只是在RestTemplate方法中加了一个注解@LoadBalanced
查看注解定义
该注解的作用是mark a RestTemplate bean to be configured to use a LoadBalancerClient
LoadBalanceClient 源码如下
对于LoadBalancerClient接口所在包 org.springframework.cloud.client.loadbalancer,
得到如下关系
LoadBalancerAutoConfiguration为实现客户端负载均衡的自动化配置类
在该自动化配置类中:
① 创建了一个LoadBalancerInterceptor的Bean,用于实现对客户端发起请求时进行拦截
,以实现客户端负载均衡
② 创建了一个RestTemplateCustomizer的Bean,用于给RestTemplate增加LoadBalancerInterceptor拦截器
③ 维护了一个被@LoadBalanced注解的RestTemplate对象列表
接下来,看一下LoadBalancerInterceptor拦截器
当一个被@LoadBalanced注解的RestTemplate对象对外发起HTTP请求时,会被LoadBalancerInterceptor类的intercept拦截。
LoadBalancerClient下的继承类RibbonLoadBalancerClient,调用execute方法
execute方法中 getServer获取具体的服务实例
可以看到这里获取具体服务实例的时候 使用了Netflix Ribbon自身的ILoadBalancer中的chooseServer方法
在ILoadBalancer接口中
对于该接口的实现,如下
那么在整合Ribbon的时候Spring Cloud默认采用了哪个具体实现呢?
在RibbonClientConfiguration配置类中,可以看到采用了ZoneAwareLoadBalancer
下面,再回到RibbonLoadBalancerClient的execute方法中,在通过ZoneAwareLoadBalancer的
chooseServer方法获取了负载均衡分配到的服务实例对象Server之后,将其内容包装成RibbonServer对象(该对象除了存储了服务实例的信息之外,还增加了服务名serviceId、是否HTTPS等其它信息),然后再回调LoadBalancerInterceptor请求拦截器中LoadBalancerRequest
的apply(final ServerInstance instance)方法,向一个实际的具体服务实例发起请求,
从而实现一开始以服务名为host的URI请求到host:post形式的实际访问地址的转换。
那么apply(final ServiceInstance instance)方法在接收到具体ServiceInstance实例后,
是如何通过LoadBalancerClient接口中的reconstructURI()操作来组成具体请求地址呢?
从apply的实现中,可以看到 先生成了ServiceRequestWrapper对象,该对象继承了
HttpRequestWrapper并重写了getURI()方法
在LoadBalancerInterceptor拦截器中,ClientHttpRequestExecution的实例具体执行
execution.execute(serviceRequest, body)时,会调用InterceptingClientHttpRequest下
InterceptingRequestExecution中execute方法
可以看到,在创建请求的时候requestFactory.createRequest(request.getURI(), request.getMethod()); 这里的request.getURI()会调用之前的ServiceRequestWrapper.getURI()
就会使用RibbonLoadBalancerClient.reconstructURI()来组织具体请求的服务实例地址