配置:和Feign一样,ribbon通过注册一个NamedContextFactory的子类SpringClientFactory(在RibbonAutoConfiguration中注册),实现不同clientName的配置的隔离。1、除了spring大工厂外,优先级最低的是SpringClientFactory实例化的时候传入的RibbonClientConfiguration(默认)2、稍高一点的是通过@RibbonClients注解导入的以default开头命名的RibbonClientSpecification,3、最高的是@RibbonClient(注意没有复数形式)导入的以服务名区别的RibbonClientSpecification。SpringClientFactory生成的时候,会把所有RibbonClientSpecification autowired到自己的属性中,之后在创建clientName对应的小工厂的时候,每个小工厂中的bean按照3-2-1的顺序注册,那么3中有的bean,2和1中再注册的时候有conditionOnMissingBean,就不会再注册了)

配置之yml:默认情况下,使用的都是1中的默认配置,所有服务都是一样的。如果用户想为某个服务单独配置的话,可以通过2(所有服务都被影响)和3(影响单个服务)的方式,在小工厂中配置单独的类,比如config,retryer,rule这些。config的配置要单独讲一下,可以通过3途径写一个DefaultClientConfigImpl去覆盖,但是这样比较复杂,更简便的办法是在yml里配置。这样做的原理是@bean的方法生成DefaultClientConfigImpl的时候,loadProperties---> loadDefaultValues--->putDefault***Property--->先根据ribbon前缀去配置文件里找,有的话,其值会取代默认值被放到properties中,再根据服务名+.ribbon作为前缀去配置文件里找,结果放到dynamicProperties中,取的时候先去dynamicProperties中取,没有再去properties取。以服务名为前缀的可以影响单个服务,否则影响全部服务。

ribbon的重试:在LoadBalancerFeignClient.executeWithLoadBalancer方法中, command.submit方法生成一个observable,在observable执行的时候,里面的核心方法是AbstractLoadBalancerAwareClient.this.execute,其实也就是HttpURLConnection的发起请求方法。如果这个方法失败了,进入的是onError,Observable的责任链会在o.retry(retryPolicy这里,重试(默认再重试一次,这个属性可以通过上面说的yml中配置RetriesOnNextServer改变)。

ribbon的熔断:ribbon在选择向哪个server发出请求的时候,selectServer方法是调用rule(RibbonClientConfiguration中的ZoneAvoidanceRule)的choose方法,通过ZoneAwareLoadBalancer把之前从eureka中获取的所有server,用predicate进行过滤,剩下的再进行轮询。那么之前如果多次(默认3)访问都失败超时的server,将会被过滤掉。所以针对掉线的server,除了重试,还有一层过滤可以进行类似断路器(只不过hystrix是服务中的方法级别的,这里是服务中的某一个server级别)的模式进行排除。

ribbon和eureka的互动:上面说到的“之前从eureka获取到的server”是存放在ZoneAwareLoadBalancer的父类BaseLoadBalancer的allServerList属性中,而eurekaClient每次从eurekaServer端获取的server信息要及时反映到ribbon中,需要通过一个定时任务(30秒一次),具体过程是:ZoneAwareLoadBalancer的父类DynamicServerListLoadBalancer的构造方法--->initWithNiwsConfig--->restOfInit--->enableAndInitLearnNewServersFeature--->PollingServerListUpdater.start--->定时任务执行updateListOfServers,调用eurekaClient.getInstancesByVipAddress,根据clientName获取serverList,赋值给allServerList。可见这个定时任务是每个clientName都有一个,只不过所用的定时任务线程池是static的只有一个。

再聊一聊ribbon的超时时间,ribbon的httpConnection发出请求使用的连接时长和请求时长是从参数options中取的,在FeignLoadBalancer的execute方法中,options是重新生成的,要看参数configOverride是不是null,这个config是LoadBalancerFeignClient的execute--->getClientConfig方法取出来的,这里面还有一个判断,就是参数的options是不是DEFAULT_OPTIONS,这个参数的options往上追溯,是通过FeignClientFactoryBean.getObject--->getTarget--->feign--->configureFeign--->configureUsingConfiguration(context, builder)--->builder.options(options)设置--->从spring工厂获取FeignRibbonClientAutoConfiguration中返回的LoadBalancerFeignClient.DEFAULT_OPTIONS,所以第一个if是成立的,那么此时的requestConfig就是RibbonClientConfiguration中注册的DefaultClientConfigImpl,所以configOverride不是null,所以新生成的这个options中的两个属性其实还是从DefaultClientConfigImpl中取(这里第二个参数是默认值,其实也是从这个impl中取,似乎有点多此一举,不过考虑到这是因为springcloud这里把ribbon和feign合用导致的,而实际上两者并不是永远绑定的),从DefaultClientConfigImpl中取属性的逻辑上文已经讲到,有动态属性和普通属性两种,可以根据服务名动态配置不同的超时时间。