SpringCloudAlibaba中使用OpenFeign时,默认的负载均衡策略是轮询调用。我们不做任何配置的时候,使用OpenFeign调用的时候,框架中是如何把负载均衡LoadBalanced和FeignClient结合到一起的?我们一起来分析一下。
位置:org.springframework.cloud.openfeign.ribbon.DefaultFeignLoadBalancedConfiguration
项目启动的时候,会用LoadBalancerFeignClient注册一个feign.Client到ioc容器中。
FeignClientFactoryBean会生成一个@FeignClient注解的对应的service实例。
位置:org.springframework.cloud.openfeign.FeignClientFactoryBean
FeignClientFactoryBean实现了FactoryBean,我们都知道,在spring中实现了FactoryBean的类在spring生命周期过程中,spring会把 getObject() 返回的实例注册到ioc容器。方便以后实例的调用。
在spring生命周期过程中会调用getObject(),从ioc容器中获取到的client就是第一步注册到ioc容器的负载均衡实例LoadBalancerFeignClient,通过builder.client(client)到Feign.builder中。如图2.2。
图2.4现在我们可以分析图2.2最后一行。return targeter.target(this, builder, context, target)。以下图2.5和图2.6为FeignClientFactoryBean的getObject最终要初始化的实例。可以明显的看到创建了一个关于SynchronousMethodHandler.Factory的实例。第一个client参数就是上面已经注册好的LoadBalancerFeignClient的实例。
图2.5 图2.6SynchronousMethodHandler 是个拦截器。项目初始话过程中,会为所有加了@FeignClient的service接口结合FeignClientFactoryBean生成对应接口的代理对象,客户端调用接口时会调用SynchronousMethodHandler的invoke方法。
图2.7从图2.9可以看出调用servcie接口时是通过 client.execute(request, options) 调用的。client即为上面已经注册好的LoadBalancerFeignClient的实例。
图2.9跟进executeWithLoadBalancer方法。
图3.1跟进submit方法
图3.2可以看到图3.3中server为null的时候,执行selectServer()方法。跟进selectServer()。
图3.3跟进getServerFromLoadBalancer()。
图3.4继续跟进,可以看到 ILoadBalancer lb = getLoadBalancer(),可以获取到要负载的对应接口的服务列表。ILoadBalancer主要就是一个负载均衡器的接口,作用就是从被负载的服务列表里选出一个服务去调用。
下图为ILoadBalancer的实现类。默认调用的是ZoneAwareLoadBalancer。
图3.5图3.5可以看出,Server svc = lb.chooseServer(loadBalancerKey),是从服务列表里面选择一个服务去调用。
跟进chooseServer()方法。默认会按照图3.6执行。
图3.6继续跟进super.chooseServer(key)方法。红框中的rule有多种实现。图3.7调用的时候默认调用的是RoundRobinRule。即轮询策略。至此,我们已探究出FeignClient默认情况下会有负载均衡,且用的是netflix的ribbon的轮询策略。
图3.7 图3.8结合图3.7从3.8中可以看出rule默认的就是 RoundRobinRule()。
位置:org.springframework.cloud.netflix.ribbon.RibbonClientConfiguration。
加载 ribbonLoadBalancer 方法时会从ioc容器中查找注册好的Rule来通过参数注入到ZoneAwareLoadBalancer实例中。如果使用默认的,此时的rule默认使用的是ZoneAvoidanceRule,即依赖的rule为RoundRobinRule roundRobinRule = new RoundRobinRule()。
所以如果想定义一个需要的rule,只需要添加以下配置就可以了。
@Configuration
public class TestConfiguration {
@Bean
public IRule ribbonRule() {
return new RandomRule(); //规则可以自己定义,也可以选择已有的
}
}
上述配置代码添加后会注册到ioc容器,下图代码为初始化 ILoadBalancer 实例时通过参数注入的方式 把ioc容器中注入好的rule实例传递给这个方法,完成负载策略的实现。