SpringCloud之Feign源码分析

Feign是SpringCloud组件中一个轻量级RESTful的HTTP服务客户端,Feign内置了Ribbon,用来做客户端负载均衡,去调用服务注册中心的服务。Feign的使用方式是:使用Feign的注解定义接口,调用这个接口,就可以调用服务注册中心的服务。

OpenFeign 是SpringCloud在Feign的基础上支持了SpringMVC的注解,如@RequestMapping等。OpenFeign 的@FeignClient可以解析SpringMVC的@RequestMapping注解下的接口,并通过动态代理的方式产生实现类,实现类中做负载均衡并调用其他服务。

核心类包括:
FeignAutoConfigurationFeignRibbonClientAutoConfiguration
注解解释:
@EnableFeignClients

Feign解析流程:

  1. @EnableFeignClients注解触发@FeignClient注解的解析,将Feign客户端抽象为FeignClientFactoryBean。
  2. Feign功能需要考虑服务治理保护涉及的熔断降级,所以通过引入HystrixTargeter进而提供相关功能。
  3. 实例化每个候选类过程中通过FactoryBean核心方法getObject对FactoryBean类型的bean做代理处理。客户端利用各自子容器创建属于自己的Feign.Builder。
  4. 最终不管是HystrixFeign还是Feign,最终都是利用ReflectiveFeign对Feign客户端实现JDK接口代理,最终维护在父级IOC容器中。

一、解析@FeignClient注解

作为 ImportBeanDefinitionRegistrar 类型的子类,其准备过程参考文章

class FeignClientsRegistrar implements ImportBeanDefinitionRegistrar,ResourceLoaderAware, EnvironmentAware {
	//metadata 启动类相关注解元信息
	// registry:容器DefaultListableBeanFactory
	@Override
	public void registerBeanDefinitions(AnnotationMetadata metadata,BeanDefinitionRegistry registry) {
		registerDefaultConfiguration(metadata, registry);//解析启动类
		registerFeignClients(metadata, registry);// 解析启动类存在的注解EnableFeignClients
	}
	
	private void registerDefaultConfiguration(AnnotationMetadata metadata,BeanDefinitionRegistry registry){
	    String name = EnableFeignClients.class.getName();
		Map<String, Object> defaultAttrs = metadata.getAnnotationAttributes(name, true);
		if (defaultAttrs != null && defaultAttrs.containsKey("defaultConfiguration")) {
			String name;
			if (metadata.hasEnclosingClass()) {
				name = "default." + metadata.getEnclosingClassName();
			}else {
				name = "default." + metadata.getClassName();// name = default.net.csdn.FeignApp
			}
			registerClientConfiguration(registry, name,defaultAttrs.get("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());
		AnnotationTypeFilter annotationTypeFilter = new AnnotationTypeFilter(FeignClient.class);
		// 从注解EnableFeignClients 获取 clients 属性。跟注解@FeignClient标明的Feign客户端一样
		final Class<?>[] clients = attrs == null ? null : (Class<?>[]) attrs.get("clients");
		// 表明@EnableFeignClients中属性clients为空,即Feign客户端是通过@FeignClient注解标注的。-- 通常使用方法
		if (clients == null || clients.length == 0) {
			scanner.addIncludeFilter(annotationTypeFilter);
			basePackages = getBasePackages(metadata);
		}else {// @EnableFeignClients 注解中利用属性 clients 获取FeignClient客户端。
			...
		}
		// 扫描 @FeignClient注解标明的Feign客户端 所在的包路径。为啥扫描? 
		// 需要将所有 Feign客户端 即接口通过FactoryBean接口功能完成代理
		for (String basePackage : basePackages) {
			Set<BeanDefinition> candidateComponents = scanner.findCandidateComponents(basePackage);
			for (BeanDefinition candidateComponent : candidateComponents) {
				if (candidateComponent instanceof AnnotatedBeanDefinition) {
					AnnotatedBeanDefinition beanDefinition = (AnnotatedBeanDefinition) candidateComponent;
					AnnotationMetadata am = beanDefinition.getMetadata();
					String canonicalName = FeignClient.class.getCanonicalName();
					// 获取到 注解FeignClient 全部的属性
					Map<String, Object> attributes = am.getAnnotationAttributes(canonicalName);
					String name = getClientName(attributes);//获取 @FeignClient注解 中name属性
					//name + "." + FeignClientSpecification:provider-service.FeignClientSpecification
					// 注册BeanDefinition,其中beanName为provider-service.FeignClientSpecification,其中
					//BeanDefinition中class属性为FeignClientSpecification
					registerClientConfiguration(registry, name,attributes.get("configuration"));
					registerFeignClient(registry, annotationMetadata, attributes);
				}
			}
		}
	}
	// attributes:注解@FeignClient的属性集合
	private void registerFeignClient(BeanDefinitionRegistry registry,AnnotationMetadata am, Map<String, 
																					Object> ab) {
		// className:net.csdn.service.FeignRemoteService
		String className = am.getClassName();
		BeanDefinitionBuilder definition = 
		BeanDefinitionBuilder.genericBeanDefinition(FeignClientFactoryBean.class);
		definition.addPropertyValue("url", getUrl(ab));
		definition.addPropertyValue("path", getPath(ab));
		String name = getName(ab);
		definition.addPropertyValue("name", name);
		String contextId = getContextId(ab);
		definition.addPropertyValue("contextId", contextId);
		definition.addPropertyValue("type", className);
		definition.addPropertyValue("decode404", ab.get("decode404"));
		definition.addPropertyValue("fallback", ab.get("fallback"));
		definition.addPropertyValue("fallbackFactory", ab.get("fallbackFactory"));
		definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
		String alias = contextId + "FeignClient";
		AbstractBeanDefinition bd = definition.getBeanDefinition();
		...
		BeanDefinitionHolder holder = new BeanDefinitionHolder(bd, className,new String[] { alias });
		//注册BeanDefinition,其中beanName为Feign客户端对应的全限定名,BeanDefinition中class属性为FeignClientFactoryBean
		BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry);
	}
	
	...
	
	private void registerClientConfiguration(BeanDefinitionRegistry r, Object name,Object configuration) {
		BeanDefinitionBuilder builder = 
			BeanDefinitionBuilder.genericBeanDefinition(FeignClientSpecification.class);
		builder.addConstructorArgValue(name);// 设置 接口Specification 的name属性
		builder.addConstructorArgValue(configuration);// 设置 接口Specification 的configuration属性
		// name + "." + FeignClientSpecification.class.getSimpleName():
		// provider-service.FeignClientSpecification
		// 将FeignClientSpecification的bean 定义信息注册到容器DefaultListableBeanFactory中
		String simpleName = FeignClientSpecification.class.getSimpleName();
		r.registerBeanDefinition(name + "." + simpleName,builder.getBeanDefinition());
	}
}

注册@FeignClient注解的Feign客户端。其中主要包括两部分:FeignClientSpecification & FeignClientFactoryBean。
在IOC容器中注册BeanDefinition时包含两部分:

  1. 一部分其beanName为provider-service.FeignClientSpecification,BeanDefinition中class属性为FeignClientSpecification。
  2. 另一部分其beanName为Feign客户端对应的全限定名【net.csdn.service.FeignRemoteService】,BeanDefinition中class属性为FeignClientFactoryBean。

其实对于FeignClientSpecification,启动类也会注册beanName为default.net.csdn.FeignApp.FeignClientSpecification。BeanDefinition中class属性为FeignClientSpecification。

二、FeignAutoConfiguration

该注解存在Spring.factories文件中,属于Spring动态注册的范畴。

@Configuration
@ConditionalOnClass(Feign.class)
@EnableConfigurationProperties({FeignClientProperties.class, FeignHttpClientProperties.class})
public class FeignAutoConfiguration {
	@Autowired(required = false)
	private List<FeignClientSpecification> configurations = new ArrayList<>();
	
	@Bean
	public FeignContext feignContext() {
		FeignContext context = new FeignContext();
		context.setConfigurations(this.configurations);
		return context;
	}
	
	@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();
		}
	}
}
  • 自定义Targeter实现类一定要加上@Primary。
  • 在实例化FeignContext过程中,会将FeignClientsConfiguration类赋值给其父类NamedContextFactory。

2.1.FeignContext

public class FeignContext extends NamedContextFactory<FeignClientSpecification> {

	public FeignContext() {
		super(FeignClientsConfiguration.class, "feign", "feign.client.name");
	}

}

所有Feign客户端共享FeignContext。
具体参考文章之NamedContextFactory。

2.2、FeignClientsConfiguration

@Configuration(proxyBeanMethods = false)
public class FeignClientsConfiguration {
	@Configuration(proxyBeanMethods = false)
	@ConditionalOnClass({ HystrixCommand.class, HystrixFeign.class })
	protected static class HystrixFeignConfiguration {

		@Bean
		@Scope("prototype")
		@ConditionalOnMissingBean
		@ConditionalOnProperty(name = "feign.hystrix.enabled")
		public Feign.Builder feignHystrixBuilder() {
			return HystrixFeign.builder();
		}
	}
}

通过开关【feign.hystrix.enabled】控制:HystrixFeign。
如上所示,实例HystrixFeign是非单例的。因为每一个Feign客户端都对应一个子容器,每个客户端都有独立的HystrixFeign,其中HystrixFeign就是由子容器创建而成的。所以在父容器中就存在与Feign客户端等量的HystrixFeign。

三、FeignRibbonClientAutoConfiguration

该注解存在Spring.factories文件中,属于Spring动态注册的范畴。

  1. 通过Import注解注入DefaultFeignLoadBalancedConfiguration。
  2. 通过DefaultFeignLoadBalancedConfiguration创建LoadBalancerFeignClient

四、FeignClientFactoryBean

其功能与Mybatis中MapperFactoryBean类似。
当类组件解析其依赖的属性FeignClient客户端组件时会通过Spring解析FactoryBean过程中调用getTarget。

public class FeignClientFactoryBean implements FactoryBean<Object>, InitializingBean {
		
	public <T> T getTarget() {
		//通过 FeignAutoConfiguration 创建FeignContext实例
		FeignContext context = applicationContext.getBean(FeignContext.class);
		// 通过 FeignContext 创建Feign.Builder。
		Feign.Builder builder = feign(context);
		//如果配置URL则直接调用,否则通过ribbon负载均衡
		if (!StringUtils.hasText(this.url)) {
			...
			HardCodedTarget target = new HardCodedTarget<>(this.type, this.name, this.url);
			// 通常选择负载均衡方式
			return (T) loadBalance(builder, context, target);
		}
		...
		HardCodedTarget target = new HardCodedTarget<>(this.type, this.name, this.url);
		return (T) targeter.target(this, builder, context,target);
	}
	
	protected Feign.Builder feign(FeignContext context) {
		FeignLoggerFactory loggerFactory = get(context, FeignLoggerFactory.class);
		// @formatter:off
		Feign.Builder builder = get(context, Feign.Builder.class)
				//以下其实就是从当前 Feign客户端的应用上下文获取Encoder、Decoder、Contract对应bean实例
				// 这些实例都是 FeignClientsConfiguration配置类中依赖的bean实例。参考 NamedContextFactory 得知,在实例化FeignClientsConfiguration过程中,就会实例化Encoder、Decoder、Contract对应bean实例
				.encoder(get(context, Encoder.class))
				.decoder(get(context, Decoder.class))
				.contract(get(context, Contract.class));
		// @formatter:on
		// builder 是从当前Feign客户端的应用上下文获取到的。核心功能就是将FeignClientProperties配置文件中Feign客户端对应的配置信息添加到 当前Feign客户端的应用上下文中,即builder中。这样实现了不同客户端配置信息最终添加到对应的IOC容器中【builder】所以是相互独立、不存在互相影响。
		configureFeign(context, builder);
		return builder;
	}
	
	protected void configureFeign(FeignContext context, Feign.Builder builder) {
		FeignClientProperties properties = this.applicationContext.getBean(FeignClientProperties.class);
		if (properties != null) {
			if (properties.isDefaultToProperties()) {
				configureUsingConfiguration(context, builder);
				// 设置默认的配置值,即跟Feign客户端没有关系。也可以称之为全局配置
				configureUsingProperties(properties.getConfig().get(properties.getDefaultConfig()),builder);
				// 设置 Feign客户端 对应的配置  contextId ~ Feign客户端的name属性
				configureUsingProperties(properties.getConfig().get(this.contextId),builder);
			}
		}
	}
	
	protected void configureUsingProperties(FeignClientProperties.FeignClientConfiguration c,Feign.Builder builder) {
		if (config.getConnectTimeout() != null && config.getReadTimeout() != null) {
			// 设置 Feign 相关的连接超时【默认10s】、读超时【默认60s】。
			builder.options(new Request.Options(c.getConnectTimeout(),c.getReadTimeout()));
		}
	}
	
	protected <T> T get(FeignContext context, Class<T> type) {
		// 此处开始创建当前Feign客户端的应用上下文,并利用其应用上下文实例化type对应的bean
		// 参考 NamedContextFactory
		T instance = context.getInstance(this.contextId, type);
		return instance;
	}
	
	protected <T> T loadBalance(Feign.Builder builder, FeignContext context,HardCodedTarget<T> target) {
	    // 优先从当前子容器获取Client,如果子容器不存在则从父容器获取。最终Client类型为~LoadBalancerFeignClient
		Client client = getOptional(context, Client.class);
		if (client != null) {
			builder.client(client);
			// 从当前Feign客户端对应应用上下文获取 HystrixTargeter
			Targeter targeter = get(context, Targeter.class);
			return targeter.target(this, builder, context, target);
		}
	}
}
  1. 通过FeignAutoConfiguration创建FeignContext。
  2. 通过FeignClientsConfiguration引入支持服务治理【熔断降级】的HystrixFeign
  3. 创建Feign.Builder过程中解析feign相关配置,例如读超时(60s)、连接超时(10s)等默认值。
  4. 优先从当前子容器获取Client,如果子容器不存在则从父容器获取。最终Client类型为~LoadBalancerFeignClient。

4.1、HystrixTargeter

class HystrixTargeter implements Targeter {

	public <T> T target(FeignClientFactoryBean factory, Feign.Builder feign,FeignContext context, 	
														Target.HardCodedTarget<T> target) {
		// 如果没有显式设置 HystrixFeign 的开关,默认Builder 为 抽象类Feign内部静态类
		if (!(feign instanceof feign.hystrix.HystrixFeign.Builder)) {
			return feign.target(target);// 忽略Feign降级功能
		}
		feign.hystrix.HystrixFeign.Builder builder = (feign.hystrix.HystrixFeign.Builder) feign;
		String name = StringUtils.isEmpty(factory.getContextId()) ? factory.getName(): factory.getContextId();
		Class<?> fallback = factory.getFallback();
		if (fallback != void.class) {// 优先通过Fallback实现Feign降级功能
			return targetWithFallback(name, context, target, builder, fallback);
		}
		Class<?> fallbackFactory = factory.getFallbackFactory();
		if (fallbackFactory != void.class) {// 其次通过FallbackFactory实现Feign降级功能
			return targetWithFallbackFactory(name, context, target, builder,fallbackFactory);
		}
		return feign.target(target);// 忽略Feign降级功能
	}
}

熔断降级功能是通过 HystrixFeign 实现的。抽象类Feign没有降级策略。

不管feign是作为抽象类Feign还是HystrixFeign,其最终返回的泛型T均为ReflectiveFeign。

4.2、 ReflectiveFeign

以HystrixFeign为例分析:

public final class HystrixFeign {
	public <T> T target(Target<T> target, FallbackFactory<? extends T> fallbackFactory) {
		// build:返回ReflectiveFeign
	  	return build(fallbackFactory).newInstance(target);
	 }
}
public class ReflectiveFeign extends Feign {
	public <T> T newInstance(Target<T> target) {
	  Map<String, MethodHandler> nameToHandler = targetToHandlersByName.apply(target);
	  Map<Method, MethodHandler> methodToHandler = new LinkedHashMap<Method, MethodHandler>();
	  List<DefaultMethodHandler> defaultMethodHandlers = new LinkedList<DefaultMethodHandler>();
	  ...
	  InvocationHandler handler = factory.create(target, methodToHandler);
	  // type:通过截图得知即为@FeignClient注解标识的某个Feign客户端
	  T proxy = (T) Proxy.newProxyInstance(target.type().getClassLoader(),
	      new Class<?>[] {target.type()}, handler);
	  return proxy;
	}
}

在这里插入图片描述
通过 HystrixTargeter 得知Feign客户端存在降级与否的区别。针对这两种区别在生成代理过程中其InvocationHandler也存在差异。如果是 HystrixFeign 则 InvocationHandler 选择 HystrixInvocationHandler子类,否则选择FeignInvocationHandler子类。

五、FeignInvocationHandler

该章节着重分析Feign客户端降级策略失效的情况。

public class ReflectiveFeign extends Feign {
	static class FeignInvocationHandler implements InvocationHandler {
	    private final Target target;
	    private final Map<Method, MethodHandler> dispatch;
	
	    FeignInvocationHandler(Target target, Map<Method, MethodHandler> dispatch) {
	      this.target = checkNotNull(target, "target");
	      this.dispatch = checkNotNull(dispatch, "dispatch for %s", target);
	    }
	
	    @Override
	    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
	      ...
	      return dispatch.get(method).invoke(args);//dispatch如图所示
	    }
	 }
}

在这里插入图片描述

final class SynchronousMethodHandler implements MethodHandler {

	public Object invoke(Object[] argv) throws Throwable {
	   RequestTemplate template = buildTemplateFromArgs.create(argv);
	   Options options = findOptions(argv);
	   Retryer retryer = this.retryer.clone();
	   while (true) {
	     try {
	       return executeAndDecode(template, options);
	     } catch (RetryableException e) {
	       retryer.continueOrPropagate(e);//重试策略
	       continue;
	     }
	   }
	}

public Object executeAndDecode(RequestTemplate template, Options options) throws Throwable {
    Request request = targetRequest(template);
    Response response = client.execute(request, options);//LoadBalancerFeignClient#execute
    long start = System.nanoTime();
    long elapsedTime = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - start);
    ...
    return response
 }

5.1、LoadBalancerFeignClient

public class LoadBalancerFeignClient implements Client {

	private CachingSpringLoadBalancerFactory lbClientFactory;

	private SpringClientFactory clientFactory;// NamedContextFactory的子类
	
	public Response execute(Request request, Request.Options options) throws IOException {
		URI asUri = URI.create(request.url());
		String clientName = asUri.getHost();// @FeignClient注解之name属性
		URI uriWithoutHost = cleanUrl(request.url(), clientName);
		FeignLoadBalancer.RibbonRequest ribbonRequest = new FeignLoadBalancer.RibbonRequest(
				this.delegate, request, uriWithoutHost);
		// 加载配置信息:ConnectTimeout、ReadTimeout
		IClientConfig requestConfig = getClientConfig(options, clientName);
		// 调用FeignLoadBalancer其抽象父类AbstractLoadBalancerAwareClient
		return lbClient(clientName).executeWithLoadBalancer(ribbonRequest,
				requestConfig).toResponse();
	}
	
	private FeignLoadBalancer lbClient(String clientName) {
		return this.lbClientFactory.create(clientName);// 创建 FeignLoadBalancer
	}
	
	IClientConfig getClientConfig(Request.Options options, String clientName) {
		IClientConfig requestConfig;
		//如果在Feign中没有显式配置read-timeout、connect-timeout,此时Feign提供默认值【读超时为60秒、连接超时为10秒】。	
		// 但是此时 options == DEFAULT_OPTIONS 条件是成立的
		if (options == DEFAULT_OPTIONS) {
			// 通过 SpringClientFactory 创建clientName对应的请求配置信息【Ribbon中read-timeout、connect-timeout的默认值为1秒】。
			requestConfig = this.clientFactory.getClientConfig(clientName);
		}else {//Feign中显式配置read-timeout、connect-timeout值
			requestConfig = new FeignOptionsClientConfig(options);
		}
		return requestConfig;
	}
}

注意:SpringClientFactory 是属于Ribbon范畴的NamedContextFactory的子类。最终是通过RibbonClientConfiguration创建requestConfig为DefaultClientConfigImpl。具体参考Ribbon相关源码解析。

DefaultClientConfigImpl其ConnectTimeout、ReadTimeout的默认值为1秒。总结为如果在Feign中没有显式配置read-timeout、connect-timeout,则对应变量的取值最终选自Ribbon中的默认值。此时Feign中ConnectTimeout、ReadTimeout的默认值将失效。

对于高版本Resilience4j实现的熔断器,如果选择DefaultTargeter则其ConnectTimeout、ReadTimeout配置完全是由FeignEncoderProperties类控制。
feign.client.config.default.connectTimeout是针对全局配置。feign.client.config.serviceName.connectTimeout是设置具体Feign客户端的配置。

5.2、FeignLoadBalancer

public abstract class AbstractLoadBalancerAwareClient extends LoadBalancerContext{

	public T executeWithLoadBalancer(final S request, final IClientConfig requestConfig) throws ClientException {
	    LoadBalancerCommand<T> command = buildLoadBalancerCommand(request, requestConfig);
	    return command.submit(//涉及响应式编程
            new ServerOperation<T>() {
                @Override
                public Observable<T> call(Server server) {// 通过负载策略获取到目标服务某个IP、端口号信息
                    URI finalUri = reconstructURIWithServer(server, request.getUri());
                    S requestForServer = (S) request.replaceUri(finalUri);
                    // FeignLoadBalancer#execute调用目标服务
                    return Observable.just(AbstractLoadBalancerAwareClient.this.execute(requestForServer, 
                    	requestConfig));
                }
            })
            .toBlocking()
            .single();
	}
}
public class LoadBalancerCommand<T> {
	public Observable<T> submit(final ServerOperation<T> operation) {
	    ...
	    // 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
	                    Observable<T> o = Observable
	                            .just(server)
	                            .concatMap(new Func1<Server, Observable<T>>() {
	                                @Override
	                                public Observable<T> call(final Server server) {
	                                    ...
	                                    return operation.call(server).doOnEach(new Observer<T>() {// 回调执行目标服务
	                                    	...
	                                    });
	                                }
	                            });
	                    return o;
	                }
	            });
	        
	    ...
	    
	    return o.onErrorResumeNext(new Func1<Throwable, Observable<T>>() {
	        @Override
	        public Observable<T> call(Throwable e) {
	            ...
	            return Observable.error(e);
	        }
	    });
	}
	
	private Observable<Server> selectServer() {
	    return Observable.create(new OnSubscribe<Server>() {
	        @Override
	        public void call(Subscriber<? super Server> next) {
	            try {
	            	// 通过上述RibbonClientConfiguration解析,获取到ribbon相关的配置、以及均衡负载策略。详情参考ribbon源码解读
	                Server server = loadBalancerContext.getServerFromLoadBalancer(loadBalancerURI, loadBalancerKey);   
	                next.onNext(server);
	                next.onCompleted();
	            } catch (Exception e) {
	                next.onError(e);
	            }
	        }
	    });
	}
}
// configOverride:feign相关配置信息
public RibbonResponse execute(RibbonRequest request, IClientConfig configOverride) throws IOException {
	Request.Options options;
	if (configOverride != null) {
		// 将Feign相关配置直接赋值给Ribbon,如果feign没有相关配置则读取ribbon相关配置
		RibbonProperties override = RibbonProperties.from(configOverride);
		options = new Request.Options(
		// connectTimeout、readTimeout均为ribbon设置的时间,默认值均为1秒。
				override.connectTimeout(this.connectTimeout),
				override.readTimeout(this.readTimeout));
	}
	else {// 使用Feign的设置值或者默认值【读超时为60秒、连接超时为10秒】。
		options = new Request.Options(this.connectTimeout, this.readTimeout);
	}
	//options包含最终的超时时间、链接超时等配置
	Response response = request.client().execute(request.toRequest(), options);
	return new RibbonResponse(request.getUri(), response);
}

源码大致意思:如果openFeign没有设置对应得超时时间,那么将会采用Ribbon的默认超时时间。

高版本:CircuitBreakerAutoConfiguration。

你可能感兴趣的:(SpringCloud,spring)