流程图
@EnableFeignClients开启Feign功能
使用时都是在spring boot 启动类加上@EnableFeignClients注解。
1 2 3
| @Import(FeignClientsRegistrar.class) public @interface EnableFeignClients { }
|
注解上有FeignClientsRegistrar类
FeignClientsRegistrar实现了ImportBeanDefinitionRegistrar接口
spring 启动时会调用registerBeanDefinitions方法
1 2 3 4 5 6 7 8
| @Override public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) { registerDefaultConfiguration(metadata, registry); registerFeignClients(metadata, registry); }
|
注册默认配置类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| #FeignClientsRegistrar private void registerDefaultConfiguration(AnnotationMetadata metadata, BeanDefinitionRegistry registry) { Map<String, Object> defaultAttrs = metadata .getAnnotationAttributes(EnableFeignClients.class.getName(), true); if (defaultAttrs != null && defaultAttrs.containsKey("defaultConfiguration")) { String name; if (metadata.hasEnclosingClass()) { name = "default." + metadata.getEnclosingClassName(); } else { name = "default." + metadata.getClassName(); } registerClientConfiguration(registry, name, defaultAttrs.get("defaultConfiguration")); } }
|
1 2 3 4 5 6 7 8 9 10 11 12
| #FeignClientsRegistrar private void registerClientConfiguration(BeanDefinitionRegistry registry, Object name, Object configuration) { BeanDefinitionBuilder builder = BeanDefinitionBuilder .genericBeanDefinition(FeignClientSpecification.class); builder.addConstructorArgValue(name); builder.addConstructorArgValue(configuration); registry.registerBeanDefinition( name + "." + FeignClientSpecification.class.getSimpleName(), builder.getBeanDefinition()); }
|
扫描@FeignClient注解
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
| #FeignClientsRegistrar 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); final Class<?>[] clients = attrs == null ? null : (Class<?>[]) attrs.get("clients"); if (clients == null || clients.length == 0) { scanner.addIncludeFilter(annotationTypeFilter); basePackages = getBasePackages(metadata); } else { for (Class<?> clazz : clients) { candidateComponents.add(new AnnotatedGenericBeanDefinition(clazz)); } } for (String basePackage : basePackages) { Set<BeanDefinition> candidateComponents = scanner .findCandidateComponents(basePackage); for (BeanDefinition candidateComponent : candidateComponents) { if (candidateComponent instanceof AnnotatedBeanDefinition) { AnnotatedBeanDefinition beanDefinition = (AnnotatedBeanDefinition) candidateComponent; AnnotationMetadata annotationMetadata = beanDefinition.getMetadata(); 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); } } } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| #FeignClientsRegistrar private void registerFeignClient(BeanDefinitionRegistry registry, AnnotationMetadata annotationMetadata, Map<String, Object> attributes) { String className = annotationMetadata.getClassName(); BeanDefinitionBuilder definition = BeanDefinitionBuilder .genericBeanDefinition(FeignClientFactoryBean.class); validate(attributes); definition.addPropertyValue("url", getUrl(attributes)); definition.addPropertyValue("path", getPath(attributes)); String name = getName(attributes); definition.addPropertyValue("name", name); String contextId = getContextId(attributes); definition.addPropertyValue("contextId", contextId); definition.addPropertyValue("type", className); definition.addPropertyValue("decode404", attributes.get("decode404")); definition.addPropertyValue("fallback", attributes.get("fallback")); definition.addPropertyValue("fallbackFactory", attributes.get("fallbackFactory")); definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE); String alias = contextId + "FeignClient"; AbstractBeanDefinition beanDefinition = definition.getBeanDefinition(); boolean primary = (Boolean) attributes.get("primary"); beanDefinition.setPrimary(primary); String qualifier = getQualifier(attributes); if (StringUtils.hasText(qualifier)) { alias = qualifier; } BeanDefinitionHolder holder = new BeanDefinitionHolder(beanDefinition, className, new String[] { alias }); BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry); }
|
这一步完成后,所有的加了@FeignClient的类就会被解析成FeignClientFactoryBean类型的BeanDefinition加入到容器中,FeignClientFactoryBean包含了@FeignClient上配置的信息,以及保存了当前添加@FeignClient注解的Class名称。之后就是Spring容器在refresh()内会去实例化该FeignClient,而FeignClientFactoryBean是FactoryBean类型,所以会调用它的getObject()进行实例化。
FeignClient实例化
1 2 3 4
| #FeignClientFactoryBean public Object getObject() throws Exception { return getTarget(); }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| #FeignClientFactoryBean <T> T getTarget() { FeignContext context = this.applicationContext.getBean(FeignContext.class); Feign.Builder builder = feign(context); if (!StringUtils.hasText(this.url)) { if (!this.name.startsWith("http")) { this.url = "http://" + this.name; } else { this.url = this.name; } this.url += cleanPath(); return (T) loadBalance(builder, context, new HardCodedTarget<>(this.type, this.name, this.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) { 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)); }
|
FeignContext在哪注入到spring容器的呢?在FeignAutoConfiguration中
FeignAutoConfiguration自动装配
1
| spring-cloud-starter-openfeign pom.xml -> spring-cloud-openfeign-core -> spring.factories -> org.springframework.cloud.openfeign.FeignAutoConfiguration
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| @Configuration @ConditionalOnClass(Feign.class) @EnableConfigurationProperties({ FeignClientProperties.class, FeignHttpClientProperties.class }) public class FeignAutoConfiguration { @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(); }
} }
|
FeignAutoConfiguration配置类会自动装配一些用来创建FeignClient实例的Bean信息。
创建生成Feign的Builder对象
1 2 3
| #FeignClientFactoryBean#getTarget()
Feign.Builder builder = feign(context);
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| #FeignClientFactoryBean 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; }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| #FeignClientFactoryBean protected void configureFeign(FeignContext context, Feign.Builder builder) { FeignClientProperties properties = this.applicationContext .getBean(FeignClientProperties.class); if (properties != null) { if (properties.isDefaultToProperties()) { configureUsingConfiguration(context, builder); configureUsingProperties( properties.getConfig().get(properties.getDefaultConfig()), builder); configureUsingProperties(properties.getConfig().get(this.contextId), builder); } else { configureUsingProperties( properties.getConfig().get(properties.getDefaultConfig()), builder); configureUsingProperties(properties.getConfig().get(this.contextId), builder); configureUsingConfiguration(context, builder); } } else { configureUsingConfiguration(context, builder); } }
|
在加载配置到builder对象中后,就是去生成代理对象的逻辑。
创建Feign代理对象
首先来看看创建负载均衡代理对象
1 2 3 4
| #FeignClientFactoryBean#getTarget()
return (T) loadBalance(builder, context, new HardCodedTarget<>(this.type, this.name, this.url));
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| #FeignClientFactoryBean 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?"); }
|
DefaultTargeter创建代理对象
1 2 3 4 5
| #FeignClientFactoryBean
Targeter targeter = get(context, Targeter.class); return targeter.target(this, builder, context, target);
|
1 2 3 4 5
| #DefaultTargeter public <T> T target(FeignClientFactoryBean factory, Feign.Builder feign, FeignContext context, Target.HardCodedTarget<T> target) { return feign.target(target); }
|
1 2 3 4 5
| #Feign public <T> T target(Target<T> target) { return build().newInstance(target); }
|
1 2 3 4 5 6 7 8 9 10 11 12 13
| #Feign.Builder public Feign build() { SynchronousMethodHandler.Factory synchronousMethodHandlerFactory = new SynchronousMethodHandler.Factory(client, retryer, requestInterceptors, logger, logLevel, decode404, closeAfterDecode, propagationPolicy); ParseHandlersByName handlersByName = new ParseHandlersByName(contract, options, encoder, decoder, queryMapEncoder, errorDecoder, synchronousMethodHandlerFactory); return new ReflectiveFeign(handlersByName, invocationHandlerFactory, queryMapEncoder); }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| #ReflectiveFeign 是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>(); for (Method method : target.type().getMethods()) { if (method.getDeclaringClass() == Object.class) { continue; } else if (Util.isDefault(method)) { DefaultMethodHandler handler = new DefaultMethodHandler(method); defaultMethodHandlers.add(handler); methodToHandler.put(method, handler); } else { methodToHandler.put(method, nameToHandler.get(Feign.configKey(target.type(), method))); } } 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; }
|
InvocationHandler对象调用invoke()
1 2 3 4 5
| #InvocationHandlerFactory.Default public InvocationHandler create(Target target, Map<Method, MethodHandler> dispatch) { return new ReflectiveFeign.FeignInvocationHandler(target, dispatch); }
|
当feignClient中的方法被调用后会执行FeignInvocationHandler的invoke方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| #FeignInvocationHandler public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 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(); } return dispatch.get(method).invoke(args); }
|
DefaultMethodHandler的invoke()
1 2 3 4 5 6 7 8
| public Object invoke(Object[] argv) throws Throwable { if (handle == null) { throw new IllegalStateException( "Default method handler invoked before proxy has been bound."); } return handle.invokeWithArguments(argv); }
|
SynchronousMethodHandler的invoke()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| 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) { try { retryer.continueOrPropagate(e); } } } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
| #SynchronousMethodHandler Object executeAndDecode(RequestTemplate template, Options options) throws Throwable { Request request = targetRequest(template); Response response; long start = System.nanoTime(); try { response = client.execute(request, options); } catch (IOException e) { } long elapsedTime = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - start); boolean shouldClose = true; try { 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; } 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 { Object result = decode(response); shouldClose = closeAfterDecode; return result; } } else if (decode404 && response.status() == 404 && void.class != metadata.returnType()) { Object result = decode(response); shouldClose = closeAfterDecode; return result; } else { throw errorDecoder.decode(metadata.configKey(), response); } } }
|
真正执行请求的client.execute(request, options)是一个接口方法,是由不同的客户端工具进行实现。如果没有导入Ribbon,那么就用feign自带的Client.Default内部进行实现。Client是一个接口。
1 2 3 4 5 6 7
| #Client.Default public Response execute(Request request, Options options) throws IOException { HttpURLConnection connection = convertAndSend(request, options); return convertResponse(connection, request); }
|
如果导入了Ribbon,那么就是LoadBalancerFeignClient实现,内部使用Ribbon进行负载均衡
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| #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(); } }
|
到这里,没有导入Hystrix创建代理对象的流程就分析完了,一些具体解析的方法并没有去详细分析,因为我们主要是理解openfeign的执行流程,所以分析创建代理对象,然后到真正执行请求的地方就行了。接下来是去分析引入了Hystrix后是如何创建代理。
HystrixTargeter创建代理对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| #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; String name = StringUtils.isEmpty(factory.getContextId()) ? factory.getName() : factory.getContextId(); SetterFactory setterFactory = getOptional(name, context, SetterFactory.class); if (setterFactory != null) { builder.setterFactory(setterFactory); } Class<?> fallback = factory.getFallback(); if (fallback != void.class) { return targetWithFallback(name, context, target, builder, fallback); } Class<?> fallbackFactory = factory.getFallbackFactory(); if (fallbackFactory != void.class) { return targetWithFallbackFactory(name, context, target, builder, fallbackFactory); } return feign.target(target); }
|
虽然导入了Hystrix,但是内部还是会判断是否设置过降级,如果没有,会回到普通的调用链路。上面的降级分支最终都会合并到一起,所以分析一个方法就行。
1 2 3 4 5 6 7 8 9
| #HystrixTargeter 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); }
|
1 2 3 4 5 6 7
| #HystrixFeign.Builder public <T> T target(Target<T> target, T fallback) { return build(fallback != null ? new FallbackFactory.Default<T>(fallback) : null) .newInstance(target); }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| #HystrixFeign.Builder Feign build(final FallbackFactory<?> nullableFallbackFactory) { super.invocationHandlerFactory(new InvocationHandlerFactory() { @Override public InvocationHandler create(Target target, Map<Method, MethodHandler> dispatch) { return new HystrixInvocationHandler(target, dispatch, setterFactory, nullableFallbackFactory); } }); super.contract(new HystrixDelegatingContract(contract)); return super.build(); }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| #HystrixInvocationHandler public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable { 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; } } }; return hystrixCommand.execute(); }
|
到这里Hystrix的代理逻辑也分析完了,它和默认创建代理对象的逻辑就是invoke()的实现不同,它只是对请求加了熔断降级的处理,其他的流程基本一致。
以上就是openfeign源码分析的整体流程,首先从feign的功能是如何开启的开始分析,然后到FeignClient是如何添加到容器当中,接着分析FeignClient是如何被代理创建,最后分析了默认方式和引入Hystrix的方式分别是如何执行的。
hystrix配置
1 2 3 4
| protected HystrixCommand(Setter setter) { this(setter.groupKey, setter.commandKey, setter.threadPoolKey, null, null, setter.commandPropertiesDefaults, setter.threadPoolPropertiesDefaults, null, null, null, null, null); }
|
发现commandPropertiesDefaults 和 threadPoolPropertiesDefaults
commandPropertiesDefaults 是命令相关参数、断路器相关参数
threadPoolPropertiesDefaults 是线程池相关参数
ribbon源码
1 2 3 4 5 6 7
| #HystrixInvocationHandler# invoke方法 return HystrixInvocationHandler.this.dispatch.get(method).invoke(args); # SynchronousMethodHandler return executeAndDecode(template, options); #SynchronousMethodHandler response = client.execute(request, options); # 这时要看是哪个client
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| #LoadBalancerFeignClient @Override 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(); } catch (ClientException e) { IOException io = findIOException(e); if (io != null) { throw io; } throw new RuntimeException(e); } }
|
1 2
| #AbstractLoadBalancerAwareClient public T executeWithLoadBalancer(final S request, final IClientConfig requestConfig)
|
1 2 3 4 5 6
| #AbstractLoadBalancerAwareClient LoadBalancerCommand<T> command = buildLoadBalancerCommand(request, requestConfig); return command.submit(....) #LoadBalancerCommand Observable<T> o = (server == null ? selectServer() : Observable.just(server))
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| #LoadBalancerCommand 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); } } }); }
|
1 2 3 4
| #LoadBalancerCommand Server server = loadBalancerContext.getServerFromLoadBalancer(loadBalancerURI, loadBalancerKey); #LoadBalancerContext Server svc = lb.chooseServer(loadBalancerKey);
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| public Server chooseServer(Object key) { if (counter == null) { counter = createCounter(); } counter.increment(); if (rule == null) { return null; } else { try { return rule.choose(key); } catch (Exception e) { logger.warn("LoadBalancer [{}]: Error choosing server for key {}", name, key, e); return null; } } }
|
1 2 3 4 5 6 7 8 9 10 11 12
| IRule (com.netflix.loadbalancer) AbstractLoadBalancerRule (com.netflix.loadbalancer) ClientConfigEnabledRoundRobinRule (com.netflix.loadbalancer) BestAvailableRule (com.netflix.loadbalancer) PredicateBasedRule (com.netflix.loadbalancer) ZoneAvoidanceRule (com.netflix.loadbalancer) AvailabilityFilteringRule (com.netflix.loadbalancer) RoundRobinRule (com.netflix.loadbalancer) WeightedResponseTimeRule (com.netflix.loadbalancer) ResponseTimeWeightedRule (com.netflix.loadbalancer) RandomRule (com.netflix.loadbalancer) RetryRule (com.netflix.loadbalancer)
|
ZoneAvoidanceRule(区域权衡策略):复合判断Server所在区域的性能和Server的可用性,轮询选择服务器。
其他规则:
BestAvailableRule(最低并发策略):会先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,然后选择一个并发量最小的服务。逐个找服务,如果断路器打开,则忽略。
RoundRobinRule(轮询策略):以简单轮询选择一个服务器。按顺序循环选择一个server。
RandomRule(随机策略):随机选择一个服务器。
AvailabilityFilteringRule(可用过滤策略):会先过滤掉多次访问故障而处于断路器跳闸状态的服务和过滤并发的连接数量超过阀值得服务,然后对剩余的服务列表安装轮询策略进行访问。
WeightedResponseTimeRule(响应时间加权策略):据平均响应时间计算所有的服务的权重,响应时间越快服务权重越大,容易被选中的概率就越高。刚启动时,如果统计信息不中,则使用RoundRobinRule(轮询)策略,等统计的信息足够了会自动的切换到WeightedResponseTimeRule。响应时间长,权重低,被选择的概率低。反之,同样道理。此策略综合了各种因素(网络,磁盘,IO等),这些因素直接影响响应时间。
RetryRule(重试策略):先按照RoundRobinRule(轮询)的策略获取服务,如果获取的服务失败则在指定的时间会进行重试,进行获取可用的服务。如多次获取某个服务失败,就不会再次获取该服务。主要是在一个时间段内,如果选择一个服务不成功,就继续找可用的服务,直到超时。