Netflix Feign - Spring Cloud 整合 Feign 源码(九)

921 阅读2分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。


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发送请求。