1. 找到ILoadBalancer的实现类
回到上一讲的代码位置:
位置在 SynchronousMethodHandler#invoke 方法上
@Override
public Object invoke(Object[] argv) throws Throwable {
RequestTemplate template = buildTemplateFromArgs.create(argv);
Retryer retryer = this.retryer.clone();
while (true) {
try {
return executeAndDecode(template);
} catch (RetryableException e) {
try {
retryer.continueOrPropagate(e);
} catch (RetryableException th) {
Throwable cause = th.getCause();
if (propagationPolicy == UNWRAP && cause != null) {
throw cause;
} else {
throw th;
}
}
if (logLevel != Logger.Level.NONE) {
logger.logRetry(metadata.configKey(), logLevel);
}
continue;
}
}
}
executeAndDecode(template) ,会调用 LoadBalancerFeignClient#execute 方法。
代码片段A:
@Override
public Response execute(Request request, Request.Options options) throws IOException {
try {
URI asUri = URI.create(request.url());
String clientName = asUri.getHost();
URI uriWithoutHost = cleanUrl(request.url(), clientName);
FeignLoadBalancer.RibbonRequest ribbonRequest = new FeignLoadBalancer.RibbonRequest(
this.delegate, request, uriWithoutHost);
IClientConfig requestConfig = getClientConfig(options, clientName);
return lbClient(clientName).executeWithLoadBalancer(ribbonRequest,
requestConfig).toResponse();
}
catch (ClientException e) {
IOException io = findIOException(e);
if (io != null) {
throw io;
}
throw new RuntimeException(e);
}
}
这里可以重点关注一下, lbClient(clientName) 的方法,我们看下他做了什么?
private FeignLoadBalancer lbClient(String clientName) {
return this.lbClientFactory.create(clientName);
}
并且是一个CachingSpringLoadBalancerFactory是一个工厂类
private CachingSpringLoadBalancerFactory lbClientFactory;
再上 CachingSpringLoadBalancerFactory#create 的代码:
public FeignLoadBalancer create(String clientName) {
FeignLoadBalancer client = this.cache.get(clientName);
if(client != null) {
return client;
}
IClientConfig config = this.factory.getClientConfig(clientName);
ILoadBalancer lb = this.factory.getLoadBalancer(clientName);
ServerIntrospector serverIntrospector = this.factory.getInstance(clientName, ServerIntrospector.class);
client = loadBalancedRetryFactory != null ? new RetryableFeignLoadBalancer(lb, config, serverIntrospector,
loadBalancedRetryFactory) : new FeignLoadBalancer(lb, config, serverIntrospector);
this.cache.put(clientName, client);
return client;
}
代码怎么去分析呢?一些我就不看了,重点是关注 ILoadBalancer接口的实现 是谁就好了的。
其实很简单了,也是老规矩,找到 RibbonClientConfiguration 这种和spring boot 整合的代码。
@Bean
@ConditionalOnMissingBean
public ILoadBalancer ribbonLoadBalancer(IClientConfig config,
ServerList<Server> serverList, ServerListFilter<Server> serverListFilter,
IRule rule, IPing ping, ServerListUpdater serverListUpdater) {
if (this.propertiesFactory.isSet(ILoadBalancer.class, name)) {
return this.propertiesFactory.get(ILoadBalancer.class, config, name);
}
return new ZoneAwareLoadBalancer<>(config, rule, ping, serverList,
serverListFilter, serverListUpdater);
}
你看,ILoadBalancer默认的实现就是ZoneAwareLoadBalancer
PS: 如果是DEBUG的情况更加简单,直接通过idea 就能发现他的实现类是什么,比自己这么去找ribbon和boot 的整合简单多了。
2. ZoneAwareLoadBalancer负载均衡的流程
上述提到,ZoneAwareLoadBalancer 是ILoadBalancer 的默认实现,那么,具体如何做负载均衡,还是要看下代码。
紧接着返回到上文的 代码片段A 上:
找到这个 executeWithLoadBalancer的方法:
这里代码就不贴了,因为涉及到RXJAVA的内容,比较复杂,也看不懂。
就理解成使用 LoadBalancerCommand 去进行调用把。
代码如下:
public T executeWithLoadBalancer(final S request, final IClientConfig requestConfig) throws ClientException {
// 会有一个LoadBalancerCommand 来做这种逻辑
LoadBalancerCommand<T> command = buildLoadBalancerCommand(request, requestConfig);
try {
return command.submit(
new ServerOperation<T>() {
@Override
public Observable<T> call(Server server) {
URI finalUri = reconstructURIWithServer(server, request.getUri());
S requestForServer = (S) request.replaceUri(finalUri);
try {
return Observable.just(AbstractLoadBalancerAwareClient.this.execute(requestForServer, requestConfig));
}
catch (Exception e) {
return Observable.error(e);
}
}
})
.toBlocking()
.single();
} catch (Exception e) {
Throwable t = e.getCause();
if (t instanceof ClientException) {
throw (ClientException) t;
} else {
throw new ClientException(e);
}
}
}