本文已参与「新人创作礼」活动,一起开启掘金创作之路。
Feign整合Ribbon及Eureka
@EnableFeignClients:扫描@FeignClient
@FeignClient:标注服务接口
@Import(FeignClientsRegistrar.class)
注册@EnableFeignClients默认Configuration的BeanDefinition
注册@FeignClient服务互相隔离的Configuration的BeanDefinition
注册@FeignClient服务互相隔离的FeignClientFactoryBean & FactoryBean的BeanDefinition
获取FeignContext & SpringClientFactory & NamedContextFactory
获取Feign.Builder
获取Client & LoadBalancerFeignClient(Client.Default装饰器模式, CachingSpringLoadBalancerFactory, SpringClientFactory)
获取Target & HardCodedTarget
获取Targeter
获取SynchronousMethodHandler.Factory
获取ParseHandlersByName
获取Feign & ReflectiveFeign
获取SynchronousMehtodHandler(RequestTemplate.Factory组合)
获取FeignInvocationHandler & InvocationHandler
获取Proxy
获取RequestTemplate
获取RequestInterceptor
获取Request
执行client.execute(Request, Options)
获取FeignLoadBalancer.RibbonRequest
获取FeignLoadBalancer
执行FeignLoadBalancer.executeWithLoadBalancer(FeignLoadBalancer.RibbonRequest,IClientConfig requestConfig)
获取Response
Feign使用的是Ribbon的ZoneAwareLoadBalancer & DynamicServerListLoadBalancer & BaseLoadBalancer & ILoadBalancer。
Ribbon的LoadBalancer内部的DomainExtractingServerList(DiscoveryEnabledNIWSServerList & ServerList) & ServerList
RibbonClientConfiguraiton初始化ZoneAwareLoadBalancer,内部是持有与eureka整合的DomainExtractingServerList(装饰者模式)
Spring Boot启动,获取Ribbon的ILoadBalancer的时候,会去获取到服务对应的独立的Spring子容器,从子容器获取对应的独立的ZoneAwareLoadBalancer,里面有DomainExtractingServerList。DomainExtractingServerList会去Eureka的注册表抓取服务对应的注册表(List<Server>)
FeignLoadBalancer封装了ZoneAwareLoadBalancer。
FeignLoadBalancer负载均衡选择Server
lbClient(clientName)从CachingSpringLoadBalancerFactory lbClientFactory中构造FeignLoadBalancer。包含Ribbon的ZoneAwareLoadBalancer,RoundRule(默认负载均衡算法)、DomianExtractingServerList(与Eureka整合)。
负载均衡
executeWithLoadBalancer(ribbonRequest, requestConfig)
LoadBalancerCommand<T> command = buildLoadBalancerCommand(request, requestConfig);
LoadBalancerCommand刚刚创建的时候,server是null,还没确定是要对哪个server发起请求。
LoadBalancerCommand负责发送请求的组件。
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();
call()方法,发送物理请求最终的一块代码,直接构造出具体的http请求的地址,然后基于底层的http通信组件,发送请求。
ServerOperation包含call()方法,被提交到LoadBalancerCommand里面。
调用toBlocking().single()方法,阻塞式同步执行,然后获取响应结果。
ServerOperation封装负载均衡选择出server,然后基于server替换掉请求URL中的eureka-provider-ribbon-feign-api-impl,然后拼接出最终的请求URL地址,然后基于底层的http组件发送请求
由LoadBalancerCommand执行,LoadBalancerCommand先使用Ribbon的ZoneAwareLoadBalancer负载均衡选择出来一个server,然后将这个server,交给SeerverOpretion中的call()方法去处理。
LoadBalancerCommand.selectServer()方法
/**
* Return an Observable that either emits only the single requested server
* or queries the load balancer for the next server on each subscription
*/
private Observable<Server> selectServer() {
return Observable.create(new OnSubscribe<Server>() {
@Override
public void call(Subscriber<? super Server> next) {
try {
Server server = loadBalancerContext.getServerFromLoadBalancer(loadBalancerURI, loadBalancerKey);
next.onNext(server);
next.onCompleted();
} catch (Exception e) {
next.onError(e);
}
}
});
}
LoadBalancerCommand执行selectServer()方法,基于Ribbon的ZoneAwareLoadBalancer的chooseServer()方法,通过负载均衡机制选择了一个server出来。
LoadBalancerCommand.submit()方法中,会调用selectServer()方法,通过Ribbon负载均衡选择一个server出来。
选择了一个server出来以后,才可以去调用ServerOperation.call()方法,由call()方法根据server发送http请求
selectServer()方法选择server,调用ServerOperation.call()方法对server发送请求。