spring-cloud-openFeign源码深度解析

如何使用spring cloud feign

@SpringBootApplication
@EnableFeignClients
public class WebApplication {

	public static void main(String[] args) {
		SpringApplication.run(WebApplication.class, args);
	}

	@FeignClient("name")
	static interface NameService {
		@RequestMapping("/")
		public String getName();
	}
}

从官网的例子中,可以看出是通过注解驱动的,所以从注解开始看起。

spring cloud feign是如何工作的

Feign涉及了两个注解,一个是@EnableFeignClients,用来开启 Feign,另一个是@FeignClient,用来标记要用 Feign 来拦截的请求接口。

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(FeignClientsRegistrar.class)
public @interface EnableFeignClients {

	String[] value() default {};

	String[] basePackages() default {};

	Class<?>[] basePackageClasses() default {};

	Class<?>[] defaultConfiguration() default {};

	Class<?>[] clients() default {};
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface FeignClient {

	@AliasFor("name")
	String value() default "";

	@Deprecated
	String serviceId() default "";

	@AliasFor("value")
	String name() default "";
	
	String qualifier() default "";

	String url() default "";

	boolean decode404() default false;

	Class<?>[] configuration() default {};

	Class<?> fallback() default void.class;

	Class<?> fallbackFactory() default void.class;

	String path() default "";

	boolean primary() default true;

}

@EnableFeignClients 是关于注解扫描的配置,比如扫描路径,配置等。@FeignClient 则是关于对该接口进行代理的时候,一些实现细节的配置,比如访问url是什么, fallback 方法,关于404的请求是抛错误还是正常返回。

先关注对EnableFeignClients 的处理,可以看出它使用了@Import(FeignClientsRegistrar.class),看名字可知是一个注册器,通过扫描某个特性的类,将bean注册到IOC中。他的生命周期方法是registerBeanDefinitions ,Spring 通过调用其 registerBeanDefinitions 方法来获取其提供的 bean definition。

public void registerBeanDefinitions(AnnotationMetadata metadata,BeanDefinitionRegistry registry) {
		//注册configuration
		registerDefaultConfiguration(metadata, registry);
		//注册注解
		registerFeignClients(metadata, registry);
	}
private void registerDefaultConfigurati(AnnotationMetadata metadata,BeanDefinitionRegistry registry) {
	//获取注解@EnableFeignClients 下设置的属性值
	Map<String, Object> defaultAttrs = metadata.getAnnotationAttributes(EnableFeignClients.class.getName(), true);

	if (defaultAttrs != null && defaultAttrs.containsKey("defaultConfiguration")) {
		String name;
		//判断传入的defaultConfiguration的是不是topClass,所谓topClass就是说此类不是别的类的内部类
		if (metadata.hasEnclosingClass()) {
			name = "default." + metadata.getEnclosingClassName();
		}
		else {
			name = "default." + metadata.getClassName();
		}
		registerClientConfiguration(registry, name,defaultAttrs.get("defaultConfiguration"));
	}
}
private void registerClientConfiguration(BeanDefinitionRegistry registry, Object name,Object configuration) {
	//加载FeignClientSpecification bean
	BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(FeignClientSpecification.class);
	builder.addConstructorArgValue(name);
	builder.addConstructorArgValue(configuration);
	//注册
	registry.registerBeanDefinition(name + "." + FeignClientSpecification.class.getSimpleName(),builder.getBeanDefinition());
}

这里会往 Registry 里面添加一个BeanDefinition,即 FeignClientSpecification,主要可调整项是通过 EnableFeignClients 注解的 defaultConfiguration 参数传入。

public void registerFeignClients(AnnotationMetadata metadata,BeanDefinitionRegistry registry) {
		ClassPathScanningCandidateComponentProvider scanner = getScanner();
		scanner.setResourceLoader(this.resourceLoader);

		Set<String> basePackages;

		Map<String, Object> attrs = metadata
				.getAnnotationAttributes(EnableFeignClients.class.getName());
		// 扫描带有FeignClient注解的类
		AnnotationTypeFilter annotationTypeFilter = new AnnotationTypeFilter(
				FeignClient.class);
		//获取@EnableFeignClients 中clients的值
		final Class<?>[] clients = attrs == null ? null
				: (Class<?>[]) attrs.get("clients");
		if (clients == null || clients.length == 0) {
			//如果没有设置,那么加入要扫描的注解和扫描的包
			scanner.addIncludeFilter(annotationTypeFilter);
			// 确定扫描的包路径列表
			basePackages = getBasePackages(metadata);
		}
		else {
			//如果设置了,最终扫出来的Bean必须是注解中设置的那些
			final Set<String> clientClasses = new HashSet<>();
			basePackages = new HashSet<>();
			for (Class<?> clazz : clients) {
				basePackages.add(ClassUtils.getPackageName(clazz));
				clientClasses.add(clazz.getCanonicalName());
			}
			AbstractClassTestingTypeFilter filter = new AbstractClassTestingTypeFilter() {
				@Override
				protected boolean match(ClassMetadata metadata) {
					String cleaned = metadata.getClassName().replaceAll("\\$", ".");
					return clientClasses.contains(cleaned);
				}
			};
			scanner.addIncludeFilter(
					new AllTypeFilter(Arrays.asList(filter, annotationTypeFilter)));
		}
		//循环扫描,并把根据注解信息,进行相关注册
		for (String basePackage : basePackages) {
			Set<BeanDefinition> candidateComponents = scanner
					.findCandidateComponents(basePackage);
			for (BeanDefinition candidateComponent : candidateComponents) {
				if (candidateComponent instanceof AnnotatedBeanDefinition) {
					// verify annotated class is an interface
					AnnotatedBeanDefinition beanDefinition = (AnnotatedBeanDefinition) candidateComponent;
					AnnotationMetadata annotationMetadata = beanDefinition.getMetadata();
					//必须注解在interface上
					Assert.isTrue(annotationMetadata.isInterface(),
							"@FeignClient can only be specified on an interface");

					Map<String, Object> attributes = annotationMetadata
							.getAnnotationAttributes(
									FeignClient.class.getCanonicalName());

					String name = getClientName(attributes);
					registerClientConfiguration(registry, name,attributes.get("configuration"));

					registerFeignClient(registry, annotationMetadata, attributes);
				}
			}
		}
	}

	private void registerFeignClient(BeanDefinitionRegistry registry,AnnotationMetadata annotationMetadata, Map<String, Object> attributes) {
		String className = annotationMetadata.getClassName();
		BeanDefinitionBuilder definition = BeanDefinitionBuilder
				.genericBeanDefinition(FeignClientFactoryBean.class);
		validate(attributes);
		//将属性设置到FeignClientFactoryBean 中
		definition.addPropertyValue("url", getUrl(attributes));
		definition.addPropertyValue("path", getPath(attributes));
		String name = getName(attributes);
		definition.addPropertyValue("name", name);
		definition.addPropertyValue("type", className);
		definition.addPropertyValue("decode404", attributes.get("decode404"));
		definition.addPropertyValue("fallback", attributes.get("fallback"));
		definition.addPropertyValue("fallbackFactory", attributes.get("fallbackFactory"));
		//设置Autowire 类型
		definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);

		String alias = name + "FeignClient";
		AbstractBeanDefinition beanDefinition = definition.getBeanDefinition();

		boolean primary = (Boolean)attributes.get("primary"); // has a default, won't be null

		beanDefinition.setPrimary(primary);

		String qualifier = getQualifier(attributes);
		if (StringUtils.hasText(qualifier)) {
			alias = qualifier;
		}
		//注册bean
		BeanDefinitionHolder holder = new BeanDefinitionHolder(beanDefinition, className,
				new String[] { alias });
		BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry);
	}

另一个往 Registry 里面添加的 BeanDefinition则是FeignClientFactoryBean,负责注册FeignClient。

也就是说,Feign的注册一共分为一下几步:

  1. 扫描@EnableFeignClients注解,如果有defaultConfiguration属性配置,则将configuration注册到BeanDefinition中,如果不指定的话,spring 提供的默认配置是FeignClientsConfiguration。
  2. 扫描 basePackage 下面所有包含了 FeignClient 注解的类
  3. 如果@EnableFeignClients中配置了clients属性,则扫描出来的bean只有在clients中配置的那些
  4. 循环扫描@FeignClient注解,如果配置了configuration,则将configuration按照 1 注册打BeanDefinition中,也就是说Feign既支持用作统一的默认的Config作为全局配置,也可以分别在@FeignClient中单独配置configuration 作为局部配置。
  5. 将@FeignClient中的其他配置设置到FeignClientFactoryBean中。

接下来来看下 FeignClientFactoryBean,它是一个工厂类,Spring Context 创建 Bean 实例时会调用它的 getObject 方法。

public Object getObject() throws Exception {
		return getTarget();
	}

	/** * @param <T> the target type of the Feign client * @return a {@link Feign} client created with the specified data and the context information */
	<T> T getTarget() {
		FeignContext context = applicationContext.getBean(FeignContext.class);
		Feign.Builder builder = feign(context);

		if (!StringUtils.hasText(this.url)) {
			//如果没有指定url,获取name值拼接默认url
			String url;
			if (!this.name.startsWith("http")) {
				url = "http://" + this.name;
			}
			else {
				url = this.name;
			}
			url += cleanPath();
			return (T) 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) {
				//使用ribbon提供的负载均衡
				// not load 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 (T) targeter.target(this, builder, context, new HardCodedTarget<>(
				this.type, this.name, url));
	}

如果指定了URL,没有指定client,那么就根据url来调用,相当于直连,没有负载均衡。如果没有指定client的话,可以使用负载均衡。现在的版本是默认开启负载均衡。

可以看出通过feign(context)方法初始化了Feign.Builder,所以着重看一下这个方法:

	protected Feign.Builder feign(FeignContext context) {
		//获取FeignClientsConfiguration 中注册的bean ,设置到feign中
		FeignLoggerFactory loggerFactory = get(context, FeignLoggerFactory.class);
		Logger logger = loggerFactory.create(this.type);

		// @formatter:off
		Feign.Builder builder = get(context, Feign.Builder.class)
				// required values
				.logger(logger)
				.encoder(get(context, Encoder.class))
				.decoder(get(context, Decoder.class))
				.contract(get(context, Contract.class));
		// @formatter:on

		configureFeign(context, builder);

		return builder;
	}

这里被设置到builder的bean来自于FeignClientsConfiguration在启动时加载到了context中,这是spring的默认配置,即使在@EnableFeignClients和@FeignClient没有配置configuration也能保证可以使用。

@Configuration
public class FeignClientsConfiguration {
	...
	@Bean
	@ConditionalOnMissingBean
	public Decoder feignDecoder() {
		return new OptionalDecoder(new ResponseEntityDecoder(new SpringDecoder(this.messageConverters)));
	}

	@Bean
	@ConditionalOnMissingBean
	public Encoder feignEncoder() {
		return new SpringEncoder(this.messageConverters);
	}

	@Bean
	@ConditionalOnMissingBean
	public Contract feignContract(ConversionService feignConversionService) {
		return new SpringMvcContract(this.parameterProcessors, feignConversionService);
	}
	...
}

那么自定义的configuration在哪里加载呢,可以看到方法feign(context)中最后一行调用了configureFeign(context, builder),来看一下这个方法。

protected void configureFeign(FeignContext context, Feign.Builder builder) {
		//获取.properties的属性
		FeignClientProperties properties = applicationContext.getBean(FeignClientProperties.class);
		if (properties != null) {
			if (properties.isDefaultToProperties()) {
				//默认为true
				configureUsingConfiguration(context, builder);
				configureUsingProperties(properties.getConfig().get(properties.getDefaultConfig()), builder);
				configureUsingProperties(properties.getConfig().get(this.name), builder);
			} else {
				configureUsingProperties(properties.getConfig().get(properties.getDefaultConfig()), builder);
				configureUsingProperties(properties.getConfig().get(this.name), builder);
				configureUsingConfiguration(context, builder);
			}
		} else {
			configureUsingConfiguration(context, builder);
		}
}
//获取用户通过configuration @Bean的自定义配置
	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);
		}
		//connectTimeoutMillis和readTimeoutMillis的默认值
		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();
		}
	}


    /*** * * @param config 获取.properties中配置的bean * @param builder feign */
	protected void configureUsingProperties(FeignClientProperties.FeignClientConfiguration config, Feign.Builder builder) {
		if (config == null) {
			return;
		}

		if (config.getLoggerLevel() != null) {
			builder.logLevel(config.getLoggerLevel());
		}
		//设置connectTimeoutMillis和readTimeoutMillis的值,这里的属性值来自于.properties配置的
		if (config.getConnectTimeout() != null && config.getReadTimeout() != null) {
			builder.options(new Request.Options(config.getConnectTimeout(), config.getReadTimeout()));
		}

		if (config.getRetryer() != null) {
			Retryer retryer = getOrInstantiate(config.getRetryer());
			builder.retryer(retryer);
		}

		if (config.getErrorDecoder() != null) {
			ErrorDecoder errorDecoder = getOrInstantiate(config.getErrorDecoder());
			builder.errorDecoder(errorDecoder);
		}

		if (config.getRequestInterceptors() != null && !config.getRequestInterceptors().isEmpty()) {
			// this will add request interceptor to builder, not replace existing
			for (Class<RequestInterceptor> bean : config.getRequestInterceptors()) {
				RequestInterceptor interceptor = getOrInstantiate(bean);
				builder.requestInterceptor(interceptor);
			}
		}

		if (config.getDecode404() != null) {
			if (config.getDecode404()) {
				builder.decode404();
			}
		}

		if (Objects.nonNull(config.getEncoder())) {
			builder.encoder(getOrInstantiate(config.getEncoder()));
		}

		if (Objects.nonNull(config.getDecoder())) {
			builder.decoder(getOrInstantiate(config.getDecoder()));
		}

		if (Objects.nonNull(config.getContract())) {
			builder.contract(getOrInstantiate(config.getContract()));
		}
	}

把配置文件中的配置项在启动时初始化到FeignClientProperties中。

  • 如果配置文件中没有配置,则将FeignClientsConfiguration中的bean作为默认值设置到builder。
  • 如果配置文件中有配置,并且用默认加载顺序时,首先加载FeignClientsConfiguration中的bean,然后加载在注解中配置的configuration,最后加载配置文件中的。
  • 如果不是默认加载顺序,则首先加载注解中配置的configuration,然后加载配置文件中的配置,最后加载FeignClientsConfiguration中的bean。注意,顺序在后面的配置会覆盖掉前面的

配置文件加载完之后,就是最关键的一步,获取 Targeter 来生成动态代理类,在 FeignAutoConfiguration 里面,配置了Target。

	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?");
	}
class HystrixTargeter implements Targeter {

	@Override
	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);
	}
}

如果 FeignClient 没有定义 fallback,或者”feign.hystrix.HystrixFeign”路径不存在,则直接用 FeignBuidler 中DefaultTargeter的 target 方法生成代理。

	@Configuration
	@ConditionalOnClass(name = "feign.hystrix.HystrixFeign")
	protected static class HystrixFeignTargeterConfiguration {
		@Bean
		@ConditionalOnMissingBean
		public Targeter feignTargeter() {
			return new HystrixTargeter();
		}
	}

	@Configuration
	@ConditionalOnMissingClass("feign.hystrix.HystrixFeign")
	protected static class DefaultFeignTargeterConfiguration {
		@Bean
		@ConditionalOnMissingBean
		public Targeter feignTargeter() {
			return new DefaultTargeter();
		}
	}
class DefaultTargeter implements Targeter {

	@Override
	public <T> T target(FeignClientFactoryBean factory, Feign.Builder feign, FeignContext context,Target.HardCodedTarget<T> target) {
		return feign.target(target);
	}
}

Feign是怎么工作的

这里会直接调用Feign的target方法:

  public <T> T target(Target<T> target) {
      return build().newInstance(target);
  }
   public Feign build() {
      SynchronousMethodHandler.Factory synchronousMethodHandlerFactory =
          new SynchronousMethodHandler.Factory(client, retryer, requestInterceptors, logger,
                                               logLevel, decode404, closeAfterDecode);
      ParseHandlersByName handlersByName =
          new ParseHandlersByName(contract, options, encoder, decoder, queryMapEncoder,
                                  errorDecoder, synchronousMethodHandlerFactory);
			//handlersByName将所有参数进行封装,并提供解析接口方法的逻辑
    	//invocationHandlerFactory是Builder的属性,默认值是InvocationHandlerFactory.Default,用创建java动态代理的InvocationHandler实现
      return new ReflectiveFeign(handlersByName, invocationHandlerFactory, queryMapEncoder);
    }

ReflectiveFeign 生成动态代理对象(newInstance)。

public <T> T newInstance(Target<T> target) {
    //为每个方法创建一个SynchronousMethodHandler对象,并放在 Map 里面。
    Map<String, MethodHandler> nameToHandler = targetToHandlersByName.apply(target);
    Map<Method, MethodHandler> methodToHandler = new LinkedHashMap<Method, MethodHandler>();
    List<DefaultMethodHandler> defaultMethodHandlers = new LinkedList<DefaultMethodHandler>();

    for (Method method : target.type().getMethods()) {
      if (method.getDeclaringClass() == Object.class) {
        continue;
      } else if(Util.isDefault(method)) {
        //如果是 default 方法,说明已经有实现了,用 DefaultHandler
        DefaultMethodHandler handler = new DefaultMethodHandler(method);
        defaultMethodHandlers.add(handler);
        methodToHandler.put(method, handler);
      } else {
        //否则就用上面的 SynchronousMethodHandler
        methodToHandler.put(method, nameToHandler.get(Feign.configKey(target.type(), method)));
      }
    }
    // 创建动态代理,factory 是 InvocationHandlerFactory.Default,创建出来的是 ReflectiveFeign.FeignInvocationHanlder,也就是说后续对方法的调用都会进入到该对象的 inovke 方法。
    InvocationHandler handler = factory.create(target, methodToHandler);
    // 创建动态代理对象
    T proxy = (T) Proxy.newProxyInstance(target.type().getClassLoader(), new Class<?>[]{target.type()}, handler);

    for(DefaultMethodHandler defaultMethodHandler : defaultMethodHandlers) {
      defaultMethodHandler.bindTo(proxy);
    }
    return proxy;
  }

这段代码主要的逻辑是:

  1. 创建MethodHandler的映射,这里创建的是实现类SynchronousMethodHandler
  2. 通过InvocationHandlerFatory创建InvocationHandler
  3. 绑定接口的default方法,通过DefaultMethodHandler绑定

	public Map<String, MethodHandler> apply(Target key) {
		//取出要实现的接口的所有方法
      List<MethodMetadata> metadata = contract.parseAndValidatateMetadata(key.type());
      Map<String, MethodHandler> result = new LinkedHashMap<String, MethodHandler>();
      for (MethodMetadata md : metadata) {
		  //根据目标接口类和方法上的注解信息判断该用哪种 buildTemplate
        BuildTemplateByResolvingArgs buildTemplate;
        if (!md.formParams().isEmpty() && md.template().bodyTemplate() == null) {
          buildTemplate = new BuildFormEncodedTemplateFromArgs(md, encoder);
        } else if (md.bodyIndex() != null) {
          buildTemplate = new BuildEncodedTemplateFromArgs(md, encoder);
        } else {
          buildTemplate = new BuildTemplateByResolvingArgs(md);
        }
		  //调用synchronousMethodHandlerFactory来生成SynchronousMethodHandler对象。这个就是对接口某个方法的实现。
        result.put(md.configKey(),
                   factory.create(key, md, buildTemplate, options, decoder, errorDecoder));
      }
      return result;
    }

这段代码的逻辑是:

  1. 通过Contract解析接口方法,生成MethodMetadata,默认的Contract解析Feign自定义的http注解
  2. 根据MethodMetadata方法元数据生成特定的RequestTemplate的工厂
  3. 使用SynchronousMethodHandler.Factory工厂创建SynchronousMethodHandler
    这里有两个工厂不要搞混淆了,SynchronousMethodHandler工厂和RequestTemplate工厂,SynchronousMethodHandler的属性包含RequestTemplate工厂
    synchronousMethodHandlerFactory 的 create 方法。
  public MethodHandler create(Target<?> target, MethodMetadata md,
                                RequestTemplate.Factory buildTemplateFromArgs,
                                Options options, Decoder decoder, ErrorDecoder errorDecoder) {
      return new SynchronousMethodHandler(target, client, retryer, requestInterceptors, logger,
                                          logLevel, md, buildTemplateFromArgs, options, decoder,
                                          errorDecoder, decode404);
    }

ReflectiveFeign.FeignInvocationHanlder 的 invoke 方法

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
      //通过动态代理实现了几个通用方法,比如 equals、toString、hasCode
      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();
      }
     //找到具体的 method 的 Handler,然后调用 invoke 方法。这样就又进入了SynchronousMethodHandler对象的 invoke 方法。
      return dispatch.get(method).invoke(args);
    }

SynchronousMethodHandler 的 invoke 方法主要是应用 encoder,decoder 以及 retry 等配置, 并且自身对于调用结果有一定的处理逻辑。

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 {
      //通过 client 获得请求的返回值
      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());
      }
    }

最后放一张读源码时画的脑图。
《spring-cloud-openFeign源码深度解析》

关于代码的详细注释,我从官网fork了一份在自己的git上,git地址是:https://github.com/brotherJ1017/spring-cloud-openfeign/tree/2.0.x

    原文作者:Spring Cloud
    原文地址: https://blog.csdn.net/sinat_29899265/article/details/86577997
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞