zoukankan      html  css  js  c++  java
  • SpringCloud之Feign实现原理

    一 开启ApacheHttpClient

      如果我们使用Apache的 HttpClient作为客户端的话,其实现逻辑就是这样的

    @Configuration
    @ConditionalOnClass({ApacheHttpClient.class})//classpath下必须得有ApacheHttpClient
    @ConditionalOnProperty(
        value = {"feign.httpclient.enabled"},
        matchIfMissing = true
    )
    class HttpClientFeignLoadBalancedConfiguration {
        //空的构造器
        HttpClientFeignLoadBalancedConfiguration() {
        }
    
        @Bean
        @ConditionalOnMissingBean({Client.class})
    public Client feignClient(
    CachingSpringLoadBalancerFactory cachingFactory,
    SpringClientFactory clientFactory, HttpClient httpClient) 
    {
            ApacheHttpClient delegate = new ApacheHttpClient(httpClient);
            return new LoadBalancerFeignClient(delegate, cachingFactory, clientFactory); // 进行包装
        }
    //…省略不相干的代码
    }

    pom文件里必须得有

         <dependency>
                <groupId>io.github.openfeign</groupId>
                <artifactId>feign-httpclient</artifactId>
                <version>9.5.1</version>
                <!--<version>${feign-httpclient.version}</version>-->
            </dependency>
            <dependency>
                <groupId>org.apache.httpcomponents</groupId>
                <artifactId>httpclient</artifactId>
            </dependency>

    观察下LoadBalancerFeignClient的代码

    public class LoadBalancerFeignClient implements Client {
    
        static final Request.Options DEFAULT_OPTIONS = new Request.Options();
    
        private final Client delegate;//实现类就是ApacheHttpClient
        private CachingSpringLoadBalancerFactory lbClientFactory;//获取ILoadBalancer的工厂类,也是Feign和Ribbon关联的纽带
        private SpringClientFactory clientFactory;
    
        public LoadBalancerFeignClient(Client delegate,
                                       CachingSpringLoadBalancerFactory lbClientFactory,
                                       SpringClientFactory clientFactory) {
            this.delegate = delegate;
            this.lbClientFactory = lbClientFactory;
            this.clientFactory = clientFactory;
        }
    @ConditionalOnProperty(
        value = {"feign.httpclient.enabled"},
        matchIfMissing = true 说明其实我们可以不配 feign.httpclient.enabled,只要在classpath下有ApacheHttpClient该配置类就会生效了

    二 Feign是怎么做负载均衡的

      LoadBalancerFeignClient

    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();
            }

      我这里截了个图

      

      clientName就是服务名

      经过转换原始的请求转成了FeignLoadBalancer.RibbonRequest

    private FeignLoadBalancer lbClient(String clientName) {
            return this.lbClientFactory.create(clientName);
        }

      clientName就是实际服务的名字

      

    public T executeWithLoadBalancer(final S request, final IClientConfig requestConfig) throws ClientException {
            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);
                }
            }
            
        }
    LoadBalancerCommand.submit
    public Observable<T> submit(final ServerOperation<T> operation) {
            final ExecutionInfoContext context = new ExecutionInfoContext();
            
            if (listenerInvoker != null) {
                try {
                    listenerInvoker.onExecutionStart();
                } catch (AbortExecutionException e) {
                    return Observable.error(e);
                }
            }
    
            final int maxRetrysSame = retryHandler.getMaxRetriesOnSameServer();
            final int maxRetrysNext = retryHandler.getMaxRetriesOnNextServer();
    
            // Use the load balancer
            Observable<T> o = 
                    (server == null ? selectServer() : Observable.just(server))
                    .concatMap(new Func1<Server, Observable<T>>() {
                        @Override
                        // Called for each server being selected
                        public Observable<T> call(Server server) {
                            context.setServer(server);
                            final ServerStats stats = loadBalancerContext.getServerStats(server);
                            
                            // Called for each attempt and retry
    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);
                    }
                }
            });
        }
    LoadBalancerContext.getServerFromLoadBalancer
    public Server getServerFromLoadBalancer(@Nullable URI original, @Nullable Object loadBalancerKey) throws ClientException {
            String host = null;
            int port = -1;
            if (original != null) {
                host = original.getHost();
            }
            if (original != null) {
                Pair<String, Integer> schemeAndPort = deriveSchemeAndPortFromPartialUri(original);        
                port = schemeAndPort.second();
            }
    
            // Various Supported Cases
            // The loadbalancer to use and the instances it has is based on how it was registered
            // In each of these cases, the client might come in using Full Url or Partial URL
            ILoadBalancer lb = getLoadBalancer();
            if (host == null) {
                // Partial URI or no URI Case
                // well we have to just get the right instances from lb - or we fall back
                if (lb != null){
                    Server svc = lb.chooseServer(loadBalancerKey);

      ILoadBalancer 在介绍Ribbon那节就介绍过了,它是负责根据负载策略选择要发送的server的

  • 相关阅读:
    记第一场省选
    POJ 2083 Fractal 分形
    CodeForces 605A Sorting Railway Cars 思维
    FZU 1896 神奇的魔法数 dp
    FZU 1893 内存管理 模拟
    FZU 1894 志愿者选拔 单调队列
    FZU 1920 Left Mouse Button 简单搜索
    FZU 2086 餐厅点餐
    poj 2299 Ultra-QuickSort 逆序对模版题
    COMP9313 week4a MapReduce
  • 原文地址:https://www.cnblogs.com/juniorMa/p/14426694.html
Copyright © 2011-2022 走看看