Feign整合Ribbon和Hystrix源码解析

我们直接来看这个类的getObject方法:

public Object getObject() throws Exception {	
        FeignContext context = applicationContext.getBean(FeignContext.class);	
        Feign.Builder builder = feign(context);	

	
        if (!StringUtils.hasText(this.url)) {	
            String url;	
            if (!this.name.startsWith("http")) {	
                url = "http://" + this.name;	
            }	
            else {	
                url = this.name;	
            }	
            url += cleanPath();	
            return loadBalance(builder, context, new HardCodedTarget<>(this.type,	
                    this.name, url));	
        }	
        if (StringUtils.hasText(this.url) && !this.url.startsWith("http")) {	
            this.url = "http://" + this.url;	
        }	
        String url = this.url + cleanPath();	
        Client client = getOptional(context, Client.class);	
        if (client != null) {	
            if (client instanceof LoadBalancerFeignClient) {	
                // not lod balancing because we have a url,	
                // but ribbon is on the classpath, so unwrap	
                client = ((LoadBalancerFeignClient)client).getDelegate();	
            }	
            builder.client(client);	
        }	
        Targeter targeter = get(context, Targeter.class);	
        return targeter.target(this, builder, context, new HardCodedTarget<>(	
                this.type, this.name, url));	
    }
  1. 获取bean:FeignContext,这个bean上篇文章已经说过了。里面包含了各个Feign客户端的配置


2. 构建Feign.Builder

设置编解码器

protected Feign.Builder feign(FeignContext context) {	
        FeignLoggerFactory loggerFactory = get(context, FeignLoggerFactory.class);	
        Logger logger = loggerFactory.create(this.type);	

	
        Feign.Builder builder = get(context, Feign.Builder.class)	
                .logger(logger)	
                .encoder(get(context, Encoder.class))	
                .decoder(get(context, Decoder.class))	
                .contract(get(context, Contract.class));	
        configureFeign(context, builder);	

	
        return builder;	
    }

设置日志、重试策略、错误code解析、超时时间、拦截器

protected void configureUsingConfiguration(FeignContext context, Feign.Builder builder) {	
        Logger.Level level = getOptional(context, Logger.Level.class);	
        if (level != null) {	
            builder.logLevel(level);	
        }	
        Retryer retryer = getOptional(context, Retryer.class);	
        if (retryer != null) {	
            builder.retryer(retryer);	
        }	
        ErrorDecoder errorDecoder = getOptional(context, ErrorDecoder.class);	
        if (errorDecoder != null) {	
            builder.errorDecoder(errorDecoder);	
        }	
        Request.Options options = getOptional(context, Request.Options.class);	
        if (options != null) {	
            builder.options(options);	
        }	
        Map<String, RequestInterceptor> requestInterceptors = context.getInstances(	
                this.name, RequestInterceptor.class);	
        if (requestInterceptors != null) {	
            builder.requestInterceptors(requestInterceptors.values());	
        }	

	
        if (decode404) {	
            builder.decode404();	
        }	
    }
  1. 判断Feign是否指定url属性,正常情况下是没有指定url的,所以会添加一个http://前缀


4. 获取代理
protected <T> T loadBalance(Feign.Builder builder, FeignContext context,	
                            HardCodedTarget<T> target) {	

	
    Client client = getOptional(context, Client.class);	
    if (client != null) {	
        builder.client(client);	
        Targeter targeter = get(context, Targeter.class);	

	
        return targeter.target(this, builder, context, target);	
    }	

	
    throw new IllegalStateException(	
                "No Feign Client for loadBalancing defined. Did you forget to include spring-cloud-starter-netflix-ribbon?");	
}

首先获取Client的实现类,这个实现类是LoadBalancerFeignClient,这个类里融合了Ribbon的相关内容。然后将Client包装到Feign.Builder中,接着获取Targeter,这里我们存在Hystrix环境,所以Targeter的实现类为HystrixTargeter

public <T> T target(FeignClientFactoryBean factory, Feign.Builder feign, FeignContext context,	
                        Target.HardCodedTarget<T> target) {	
        if (!(feign instanceof feign.hystrix.HystrixFeign.Builder)) {	
            return feign.target(target);	
        }	
        feign.hystrix.HystrixFeign.Builder builder = (feign.hystrix.HystrixFeign.Builder) feign;	
        SetterFactory setterFactory = getOptional(factory.getName(), context,	
            SetterFactory.class);	
        if (setterFactory != null) {	
            builder.setterFactory(setterFactory);	
        }	
        Class<?> fallback = factory.getFallback();	
        if (fallback != void.class) {	
            return targetWithFallback(factory.getName(), context, target, builder, fallback);	
        }	
        Class<?> fallbackFactory = factory.getFallbackFactory();	
        if (fallbackFactory != void.class) {	
            return targetWithFallbackFactory(factory.getName(), context, target, builder, fallbackFactory);	
        }	

	
        return feign.target(target);	
    }

接着以Feign客户端设置了fallback为例

 private <T> T targetWithFallback(String feignClientName, FeignContext context,Target.HardCodedTarget<T> target,HystrixFeign.Builder builder, Class<?> fallback) {	
        T fallbackInstance = getFromContext("fallback", feignClientName, context, fallback, target.type());	
        return builder.target(target, fallbackInstance);	
    }

接着就是这个代理的创建,现在这个代理中包含了Ribbon和Hystrix。而这个代理类的实现类是HystrixInvocationHandler

public Object invoke(final Object proxy, final Method method, final Object[] args)	
      throws Throwable {	
    // early exit if the invoked method is from java.lang.Object	
    // code is the same as ReflectiveFeign.FeignInvocationHandler	
    if ("equals".equals(method.getName())) {	
      try {	
        Object otherHandler =	
            args.length > 0 && args[0] != null ? Proxy.getInvocationHandler(args[0]) : null;	
        return equals(otherHandler);	
      } catch (IllegalArgumentException e) {	
        return false;	
      }	
    } else if ("hashCode".equals(method.getName())) {	
      return hashCode();	
    } else if ("toString".equals(method.getName())) {	
      return toString();	
    }	

	
    HystrixCommand<Object> hystrixCommand = new HystrixCommand<Object>(setterMethodMap.get(method)) {	
      @Override	
      protected Object run() throws Exception {	
        try {	
          return HystrixInvocationHandler.this.dispatch.get(method).invoke(args);	
        } catch (Exception e) {	
          throw e;	
        } catch (Throwable t) {	
          throw (Error) t;	
        }	
      }	

	
      @Override	
      protected Object getFallback() {	
        if (fallbackFactory == null) {	
          return super.getFallback();	
        }	
        try {	
          Object fallback = fallbackFactory.create(getExecutionException());	
          Object result = fallbackMethodMap.get(method).invoke(fallback, args);	
          if (isReturnsHystrixCommand(method)) {	
            return ((HystrixCommand) result).execute();	
          } else if (isReturnsObservable(method)) {	
            // Create a cold Observable	
            return ((Observable) result).toBlocking().first();	
          } else if (isReturnsSingle(method)) {	
            // Create a cold Observable as a Single	
            return ((Single) result).toObservable().toBlocking().first();	
          } else if (isReturnsCompletable(method)) {	
            ((Completable) result).await();	
            return null;	
          } else {	
            return result;	
          }	
        } catch (IllegalAccessException e) {	
          // shouldn't happen as method is public due to being an interface	
          throw new AssertionError(e);	
        } catch (InvocationTargetException e) {	
          // Exceptions on fallback are tossed by Hystrix	
          throw new AssertionError(e.getCause());	
        }	
      }	
    };	

	
    if (isReturnsHystrixCommand(method)) {	
      return hystrixCommand;	
    } else if (isReturnsObservable(method)) {	
      // Create a cold Observable	
      return hystrixCommand.toObservable();	
    } else if (isReturnsSingle(method)) {	
      // Create a cold Observable as a Single	
      return hystrixCommand.toObservable().toSingle();	
    } else if (isReturnsCompletable(method)) {	
      return hystrixCommand.toObservable().toCompletable();	
    }	
    return hystrixCommand.execute();	
  }

这里就利用到了Hystrix的知识,更多关于Hystrix的内容可以参考之前的文章

接着深入invoke方法

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) {	
            retryer.continueOrPropagate(e);	
            if (logLevel != Logger.Level.NONE) {	
                logger.logRetry(metadata.configKey(), logLevel);	
            }	
            continue;	
        }	
    }	
}

这里构建了请求信息和重试策略,具体请求内容在下面:

Object executeAndDecode(RequestTemplate template) throws Throwable {	
    Request request = targetRequest(template);	

	
    if (logLevel != Logger.Level.NONE) {	
      logger.logRequest(metadata.configKey(), logLevel, request);	
    }	

	
    Response response;	
    long start = System.nanoTime();	
    try {	
      response = client.execute(request, options);	
      // ensure the request is set. TODO: remove in Feign 10	
      response.toBuilder().request(request).build();	
    } catch (IOException e) {	
      if (logLevel != Logger.Level.NONE) {	
        logger.logIOException(metadata.configKey(), logLevel, e, elapsedTime(start));	
      }	
      throw errorExecuting(request, e);	
    }	
    long elapsedTime = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - start);	

	
    boolean shouldClose = true;	
    try {	
      if (logLevel != Logger.Level.NONE) {	
        response =	
            logger.logAndRebufferResponse(metadata.configKey(), logLevel, response, elapsedTime);	
        // ensure the request is set. TODO: remove in Feign 10	
        response.toBuilder().request(request).build();	
      }	
      if (Response.class == metadata.returnType()) {	
        if (response.body() == null) {	
          return response;	
        }	
        if (response.body().length() == null ||	
                response.body().length() > MAX_RESPONSE_BUFFER_SIZE) {	
          shouldClose = false;	
          return response;	
        }	
        // Ensure the response body is disconnected	
        byte[] bodyData = Util.toByteArray(response.body().asInputStream());	
        return response.toBuilder().body(bodyData).build();	
      }	
      if (response.status() >= 200 && response.status() < 300) {	
        if (void.class == metadata.returnType()) {	
          return null;	
        } else {	
          return decode(response);	
        }	
      } else if (decode404 && response.status() == 404 && void.class != metadata.returnType()) {	
        return decode(response);	
      } else {	
        throw errorDecoder.decode(metadata.configKey(), response);	
      }	
    } catch (IOException e) {	
      if (logLevel != Logger.Level.NONE) {	
        logger.logIOException(metadata.configKey(), logLevel, e, elapsedTime);	
      }	
      throw errorReading(request, response, e);	
    } finally {	
      if (shouldClose) {	
        ensureClosed(response.body());	
      }	
    }	
  }

再往下深入就是Ribbon的负载均衡了,具体内容可以参考之前的文章

往期好文

640?wx_fmt=png

好文章就该:收藏、转发、在看!!!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值