Spring Cloud与微服务构建(七)声明式调用Feign 7.6 Feign是如何实现负载均衡的

FeignRibbonClientAutoConfiguration类配置了client.default的类型(包括HttpURLConnection、OkHttp和HttpClient),最终向容器注入的是Client的实现类LoadBalancerFeignClient,即负载均衡客户端。查看LoadalancerFeignClient类中的execute方法,即执行请求的方法,代码如下:

    public Response execute(Request request, Options options) throws IOException {
        try {
            URI asUri = URI.create(request.url());
            String clientName = asUri.getHost();
            URI uriWithoutHost = cleanUrl(request.url(), clientName);
            RibbonRequest ribbonRequest = new RibbonRequest(this.delegate, request, uriWithoutHost);
            IClientConfig requestConfig = this.getClientConfig(options, clientName);
            return ((RibbonResponse)this.lbClient(clientName).executeWithLoadBalancer(ribbonRequest, requestConfig)).toResponse();
        } catch (ClientException var8) {
            IOException io = this.findIOException(var8);
            if (io != null) {
                throw io;
            } else {
                throw new RuntimeException(var8);
            }
        }
    }

其中有一个executeWithLoadBalancer()方法,即通过负载均衡的方式来执行网络请求,代码如下:

    public T executeWithLoadBalancer(final S request, final IClientConfig requestConfig) throws ClientException {
        RequestSpecificRetryHandler handler = this.getRequestSpecificRetryHandler(request, requestConfig);
        LoadBalancerCommand command = LoadBalancerCommand.builder().withLoadBalancerContext(this).withRetryHandler(handler).withLoadBalancerURI(request.getUri()).build();

        try {
            return (IResponse)command.submit(new ServerOperation<T>() {
                public Observable<T> call(Server server) {
                    URI finalUri = AbstractLoadBalancerAwareClient.this.reconstructURIWithServer(server, request.getUri());
                    ClientRequest requestForServer = request.replaceUri(finalUri);

                    try {
                        return Observable.just(AbstractLoadBalancerAwareClient.this.execute(requestForServer, requestConfig));
                    } catch (Exception var5) {
                        return Observable.error(var5);
                    }
                }
            }).toBlocking().single();
        } catch (Exception var7) {
            Throwable t = var7.getCause();
            if (t instanceof ClientException) {
                throw (ClientException)t;
            } else {
                throw new ClientException(var7);
            }
        }
    }

在上述代码中,有一个submit()方法,进入submit()方法的内部可以看出它是LoadBalancerCommand类的方法,代码如下:

        Observable<T> o = (this.server == null ? this.selectServer() : Observable.just(this.server)).concatMap(new Func1<Server, Observable<T>>() {
            public Observable<T> call(Server server) {
                context.setServer(server);
                final ServerStats stats = LoadBalancerCommand.this.loadBalancerContext.getServerStats(server);
                Observable<T> o = Observable.just(server).concatMap(new Func1<Server, Observable<T>>() {
                    public Observable<T> call(final Server server) {
                        context.incAttemptCount();
                        LoadBalancerCommand.this.loadBalancerContext.noteOpenConnection(stats);
                        if (LoadBalancerCommand.this.listenerInvoker != null) {
                            try {
                                LoadBalancerCommand.this.listenerInvoker.onStartWithServer(context.toExecutionInfo());
                            } catch (AbortExecutionException var3) {
                                return Observable.error(var3);
                            }
                        }

                        final Stopwatch tracer = LoadBalancerCommand.this.loadBalancerContext.getExecuteTracer().start();
                        return operation.call(server).doOnEach(new Observer<T>() {
                            private T entity;

                            public void onCompleted() {
                                this.recordStats(tracer, stats, this.entity, (Throwable)null);
                            }

                            public void onError(Throwable e) {
                                this.recordStats(tracer, stats, (Object)null, e);
                                LoadBalancerCommand.logger.debug("Got error {} when executed on server {}", e, server);
                                if (LoadBalancerCommand.this.listenerInvoker != null) {
                                    LoadBalancerCommand.this.listenerInvoker.onExceptionWithServer(e, context.toExecutionInfo());
                                }

                            }

                            public void onNext(T entity) {
                                this.entity = entity;
                                if (LoadBalancerCommand.this.listenerInvoker != null) {
                                    LoadBalancerCommand.this.listenerInvoker.onExecutionSuccess(entity, context.toExecutionInfo());
                                }

                            }

                            private void recordStats(Stopwatch tracerx, ServerStats statsx, Object entity, Throwable exception) {
                                tracerx.stop();
                                LoadBalancerCommand.this.loadBalancerContext.noteRequestCompletion(statsx, entity, exception, tracerx.getDuration(TimeUnit.MILLISECONDS), LoadBalancerCommand.this.retryHandler);
                            }
                        });
                    }
                });
                if (maxRetrysSame > 0) {
                    o = o.retry(LoadBalancerCommand.this.retryPolicy(maxRetrysSame, true));
                }

                return o;
            }
        });
        if (maxRetrysNext > 0 && this.server == null) {
            o = o.retry(this.retryPolicy(maxRetrysNext, false));
        }

在上述代码中,有一个selectServe()方法,该方法是选择服务进行负载均衡的方法,代码如下:

    private Observable<Server> selectServer() {
        return Observable.create(new OnSubscribe<Server>() {
            public void call(Subscriber<? super Server> next) {
                try {
                    Server server = LoadBalancerCommand.this.loadBalancerContext.getServerFromLoadBalancer(LoadBalancerCommand.this.loadBalancerURI, LoadBalancerCommand.this.loadBalancerKey);
                    next.onNext(server);
                    next.onCompleted();
                } catch (Exception var3) {
                    next.onError(var3);
                }

            }
        });
    }

由上术代码可知,最终负载均衡交给loadBalancerContext来处理,即上一章讲述的Ribbon,这里不再重复。

总的来说,Feign的源码实现过程如下。

(1)首先通过@EnableFeignClients注解开启FeignClient的功能。只有这个注解存在,才会在程序启动时开启对@FeignClient注解的包扫描。
(2)根据Feign的规则实现接口,并在接口上面加上@FeignClient注解。
(3)程序启动后,会进行包扫描,扫描所有的@FeignClient的注解的类,并将这些信息注入IoC容器中。
(4)当接口的方法被调用时,通过JDK的代理来生成具体的RequestTemplate模板对象。
(5)根据RequestTemplate再生成Http请求的Request对象。
(6)Request对象交给Client云处理,其中Client的网络请求框架可以是HttpURLConnection、HttpClient和OkHttp。
(7)最后Client被封装到LoadBalanceClient类,这个类结合类Ribbon做到了负载均衡。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值