专栏电商日志财经减肥爱情
投稿投诉
爱情常识
搭配分娩
减肥两性
孕期塑形
财经教案
论文美文
日志体育
养生学堂
电商科学
头戴业界
专栏星座
用品音乐

Ribbon源码解析

  什么是Ribbon
  Ribbon是Netflix公司开源的一个负载均衡的项目,它属于上述的第二种,是一个客户端负载均衡器,运行在客户端上。它是一个经过了云端测试的IPC库,可以很好地控制HTTP和TCP客户端的一些行为。Feign已经默认使用了Ribbon。负载均衡容错多协议(HTTP,TCP,UDP)支持异步和反应模型缓存和批处理RestTemplate和Ribbon相结合
  Ribbon在Netflix组件是非常重要的一个组件,在Zuul中使用Ribbon做负载均衡,以及Feign组件的结合等。在SpringCloud中,作为开发中,做的最多的可能是将RestTemplate和Ribbon相结合,你可能会这样写:ConfigurationpublicclassRibbonConfig{BeanLoadBalancedRestTemplaterestTemplate(){returnnewRestTemplate();}}
  消费另外一个的服务的接口,差不多是这样的:ServicepublicclassRibbonService{AutowiredRestTemplaterestTemplate;publicStringhi(Stringname){returnrestTemplate。getForObject(http:eurekaclienthi?namename,String。class);}}深入理解RibbonRibbonAutoConfiguration
  Ribbon的自动配置类,配置Ribbon负载均衡客户端(LoadBalancerClient)ConfigurationConditional(RibbonAutoConfiguration。RibbonClassesConditions。class)RibbonClientsAutoConfigureAfter(nameorg。springframework。cloud。netflix。eureka。EurekaClientAutoConfiguration)AutoConfigureBefore({LoadBalancerAutoConfiguration。class,AsyncLoadBalancerAutoConfiguration。class})EnableConfigurationProperties({RibbonEagerLoadProperties。class,ServerIntrospectorProperties。class})publicclassRibbonAutoConfiguration{BeanpublicSpringClientFactoryspringClientFactory(){SpringClientFactoryfactorynewSpringClientFactory();factory。setConfigurations(this。configurations);returnfactory;}BeanConditionalOnMissingBean(LoadBalancerClient。class)publicLoadBalancerClientloadBalancerClient(){returnnewRibbonLoadBalancerClient(springClientFactory());}}RibbonEurekaAutoConfiguration在RibbonAutoConfiguration后启用Configuration(proxyBeanMethodsfalse)EnableConfigurationPropertiesConditionalOnRibbonAndEurekaEnabledAutoConfigureAfter(RibbonAutoConfiguration。class)RibbonClients(defaultConfigurationEurekaRibbonClientConfiguration。class)publicclassRibbonEurekaAutoConfiguration{}EurekaRibbonClientConfiguration
  使用Eurekaclient去获取Server节点信息Configuration(proxyBeanMethodsfalse)publicclassEurekaRibbonClientConfiguration{BeanConditionalOnMissingBeanpublicIPingribbonPing(IClientConfigconfig){if(this。propertiesFactory。isSet(IPing。class,serviceId)){returnthis。propertiesFactory。get(IPing。class,config,serviceId);}NIWSDiscoveryPingpingnewNIWSDiscoveryPing();ping。initWithNiwsConfig(config);returnping;}BeanConditionalOnMissingBeanpublicServerListlt;?ribbonServerList(IClientConfigconfig,ProviderEurekaClienteurekaClientProvider){if(this。propertiesFactory。isSet(ServerList。class,serviceId)){returnthis。propertiesFactory。get(ServerList。class,config,serviceId);}DiscoveryEnabledNIWSServerListdiscoveryServerListnewDiscoveryEnabledNIWSServerList(config,eurekaClientProvider);DomainExtractingServerListserverListnewDomainExtractingServerList(discoveryServerList,config,this。approximateZoneFromHostname);returnserverList;}}
  以上配置类在eurekaclient的METAINFSpring。factories文件中配置org。springframework。boot。autoconfigure。EnableAutoConfigurationorg。springframework。cloud。netflix。eureka。config。EurekaClientConfigServerAutoConfiguration,org。springframework。cloud。netflix。eureka。config。EurekaDiscoveryClientConfigServiceAutoConfiguration,org。springframework。cloud。netflix。eureka。EurekaClientAutoConfiguration,org。springframework。cloud。netflix。ribbon。eureka。RibbonEurekaAutoConfiguration,org。springframework。cloud。netflix。eureka。EurekaDiscoveryClientConfiguration,org。springframework。cloud。netflix。eureka。reactive。EurekaReactiveDiscoveryClientConfigurationDiscoveryEnabledNIWSServerList
  通过Eurekaclient获取服务节点信息列表,并提供给DynamicServerListLoadBalancerTheserverlistclassthatfetchestheserverinformationfromEurekaclient。ServerListisusedbyDynamicServerListLoadBalancertogetserverlistdynamically。publicclassDiscoveryEnabledNIWSServerListextendsAbstractServerListDiscoveryEnabledServer{privateListDiscoveryEnabledServerobtainServersViaDiscovery(){ListDiscoveryEnabledServerserverListnewArrayListDiscoveryEnabledServer();EurekaClienteurekaClienteurekaClientProvider。get();if(vipAddresses!null){for(StringvipAddress:vipAddresses。split(,)){iftargetRegionisnull,itwillbeinterpretedasthesameregionofclientListInstanceInfolistOfInstanceInfoeurekaClient。getInstancesByVipAddress(vipAddress,isSecure,targetRegion);for(InstanceInfoii:listOfInstanceInfo){if(ii。getStatus()。equals(InstanceStatus。UP)){。。。。。。DiscoveryEnabledServerdescreateServer(ii,isSecure,shouldUseIpAddr);serverList。add(des);}}}}}LoadBalancerClient
  在Ribbon中一个非常重要的组件为LoadBalancerClient,它作为负载均衡的一个客户端。它在springcloudcommons包下:的LoadBalancerClient是一个接口,它继承ServiceInstanceChooser,它的实现类是RibbonLoadBalancerClient,这三者之间的关系如下图:
  其中LoadBalancerClient接口,有如下三个方法,其中excute()为执行请求,reconstructURI()用来重构url:packageorg。springframework。cloud。client。loadbalancer;publicinterfaceLoadBalancerClientextendsServiceInstanceChooser{TTexecute(StringserviceId,LoadBalancerRequestTrequest)throwsIOException;TTexecute(StringserviceId,ServiceInstanceserviceInstance,LoadBalancerRequestTrequest)throwsIOException;URIreconstructURI(ServiceInstanceinstance,URIoriginal);}
  ServiceInstanceChooser接口,主要有一个方法,用来根据serviceId来获取ServiceInstance,代码如下:publicinterfaceServiceInstanceChooser{ServiceInstancechoose(StringserviceId);}
  LoadBalancerClient的实现类为RibbonLoadBalancerClient,这个类是非常重要的一个类,最终的负载均衡的请求处理,由它来执行。它的部分源码如下:publicclassRibbonLoadBalancerClientimplementsLoadBalancerClient{省略代码publicServiceInstancechoose(StringserviceId,Objecthint){ServerservergetServer(getLoadBalancer(serviceId),hint);if(servernull){returnnull;}returnnewRibbonServer(serviceId,server,isSecure(server,serviceId),serverIntrospector(serviceId)。getMetadata(server));}protectedServergetServer(ILoadBalancerloadBalancer,Objecthint){if(loadBalancernull){returnnull;}Usedefaultonanullhint,orjustpassiton?returnloadBalancer。chooseServer(hint!null?hint:default);}protectedServergetServer(ILoadBalancerloadBalancer){if(loadBalancernull){returnnull;}returnloadBalancer。chooseServer(default);TODO:betterhandlingofkey}protectedILoadBalancergetLoadBalancer(StringserviceId){returnthis。clientFactory。getLoadBalancer(serviceId);}。。。省略代码
  在RibbonLoadBalancerClient的源码中,其中choose()方法是选择具体服务实例的一个方法。该方法通过getServer()方法去获取实例,经过源码跟踪,最终交给了ILoadBalancer类去选择服务实例。
  ILoadBalancer在ribbonloadbalancer的jar包下,它是定义了实现软件负载均衡的一个接口,它需要一组可供选择的服务注册列表信息,以及根据特定方法去选择服务,它的源码如下:publicinterfaceILoadBalancer{添加服务节点publicvoidaddServers(ListServernewServers);根据key选择服务节点publicServerchooseServer(Objectkey);publicvoidmarkServerDown(Serverserver);可达服务列表publicListServergetReachableServers();所有服务节点publicListServergetAllServers();}
  其中,addServers()方法是添加一个Server集合;chooseServer()方法是根据key去获取Server;markServerDown()方法用来标记某个服务下线;getReachableServers()获取可用的Server集合;getAllServers()获取所有的Server集合。DynamicServerListLoadBalancer
  它的继承类为BaseLoadBalancer,它的实现类为DynamicServerListLoadBalancer,这三者之间的关系如下:
  查看上述三个类的源码,可用发现,配置以下信息,IClientConfig、IRule、IPing、ServerList、ServerListFilter和ILoadBalancer,查看BaseLoadBalancer类,它默认的情况下,实现了以下配置:IClientConfigribbonClientConfig:DefaultClientConfigImpl配置IRuleribbonRule:RoundRobinRule路由策略IPingribbonPing:DummyPingServerListribbonServerList:ConfigurationBasedServerListServerListFilterribbonServerListFilter:ZonePreferenceServerListFilterILoadBalancerribbonLoadBalancer:ZoneAwareLoadBalancerIClientConfig
  IClientConfig用于对客户端或者负载均衡的配置,它的默认实现类为DefaultClientConfigImpl。IRule
  IRule用于复杂均衡的策略,它有三个方法,其中choose()是根据key来获取server,setLoadBalancer()和getLoadBalancer()是用来设置和获取ILoadBalancer的,它的源码如下:publicinterfaceIRule{publicServerchoose(Objectkey);publicvoidsetLoadBalancer(ILoadBalancerlb);publicILoadBalancergetLoadBalancer();}
  IRule有很多默认的实现类,这些实现类根据不同的算法和逻辑来处理负载均衡。Ribbon实现的IRule有一下。在大多数情况下,这些默认的实现类是可以满足需求的,如果有特性的需求,可以自己实现。BestAvailableRule选择最小请求数ClientConfigEnabledRoundRobinRule轮询RandomRule随机选择一个serverRoundRobinRule轮询选择serverRetryRule根据轮询的方式重试WeightedResponseTimeRule根据响应时间去分配一个weight,weight越低,被选择的可能性就越低ZoneAvoidanceRule根据server的zone区域和可用性来轮询选择
  RoundRobinRule:轮询负载规则实现publicclassRoundRobinRuleextendsAbstractLoadBalancerRule{原子整数,下一次获取Server节点的indexprivateAtomicIntegernextServerCyclicCounter;publicServerchoose(ILoadBalancerlb,Objectkey){if(lbnull){log。warn(noloadbalancer);returnnull;}Serverservernull;intcount0;while(servernullcount10){ListServerreachableServerslb。getReachableServers();ListServerallServerslb。getAllServers();intupCountreachableServers。size();intserverCountallServers。size();if((upCount0)(serverCount0)){log。warn(Noupserversavailablefromloadbalancer:lb);returnnull;}intnextServerIndexincrementAndGetModulo(serverCount);serverallServers。get(nextServerIndex);if(servernull){Transient。Thread。yield();continue;}if(server。isAlive()(server。isReadyToServe())){return(server);}Next。servernull;}if(count10){log。warn(Noavailablealiveserversafter10triesfromloadbalancer:lb);}returnserver;}Inspiredbytheimplementationof{linkAtomicIntegerincrementAndGet()}。parammoduloThemodulotoboundthevalueofthecounter。returnThenextvalue。privateintincrementAndGetModulo(intmodulo){for(;;){intcurrentnextServerCyclicCounter。get();intnext(current1)modulo;if(nextServerCyclicCounter。compareAndSet(current,next))returnnext;}})
  BestAvailableRule:最少并发请求负载规则publicclassBestAvailableRuleextendsClientConfigEnabledRoundRobinRule{privateLoadBalancerStatsloadBalancerStats;OverridepublicServerchoose(Objectkey){if(loadBalancerStatsnull){returnsuper。choose(key);}ListServerserverListgetLoadBalancer()。getAllServers();intminimalConcurrentConnectionsInteger。MAXVALUE;longcurrentTimeSystem。currentTimeMillis();Serverchosennull;for(Serverserver:serverList){获取服务节点的状态信息,保存在Guava缓存中ServerStatsserverStatsloadBalancerStats。getSingleServerStat(server);if(!serverStats。isCircuitBreakerTripped(currentTime)){intconcurrentConnectionsserverStats。getActiveRequestsCount(currentTime);if(concurrentConnectionsminimalConcurrentConnections){minimalConcurrentConnectionsconcurrentConnections;chosenserver;}}}if(chosennull){returnsuper。choose(key);}else{returnchosen;}}OverridepublicvoidsetLoadBalancer(ILoadBalancerlb){super。setLoadBalancer(lb);if(lbinstanceofAbstractLoadBalancer){loadBalancerStats((AbstractLoadBalancer)lb)。getLoadBalancerStats();}}}IPing
  IPing是用来想server发生ping,来判断该server是否有响应,从而判断该server是否可用。它有一个isAlive()方法,它的源码如下:publicinterfaceIPing{publicbooleanisAlive(Serverserver);}
  IPing的实现类有PingUrl、PingConstant、NoOpPing、DummyPing和NIWSDiscoveryPing。它门之间的关系如下:
  PingUrl真实的去ping某个url,判断其是否alivePingConstant固定返回某服务是否可用,默认返回true,即可用NoOpPing不去ping,直接返回true,即可用。DummyPing直接返回true,并实现了initWithNiwsConfig方法。NIWSDiscoveryPing,根据DiscoveryEnabledServer的InstanceInfo的InstanceStatus去判断,如果为InstanceStatus。UP,则为可用,否则不可用。ServerList
  ServerList是定义获取所有的server的注册列表信息的接口,它的代码如下:publicinterfaceServerListTextendsServer{publicListTgetInitialListOfServers();publicListTgetUpdatedListOfServers();}ServerListFilter
  ServerListFilter接口,定于了可根据配置去过滤或者根据特性动态获取符合条件的server列表的方法,代码如下:publicinterfaceServerListFilterTextendsServer{publicListTgetFilteredListOfServers(ListTservers);}DynamicServerListLoadBalancer
  阅读DynamicServerListLoadBalancer的源码,DynamicServerListLoadBalancer的构造函数中有个initWithNiwsConfig()方法。在改方法中,经过一系列的初始化配置,最终执行了restOfInit()方法。其代码如下:publicDynamicServerListLoadBalancer(IClientConfigclientConfig){initWithNiwsConfig(clientConfig);}OverridepublicvoidinitWithNiwsConfig(IClientConfigclientConfig){try{super。initWithNiwsConfig(clientConfig);StringniwsServerListClassNameclientConfig。getPropertyAsString(CommonClientConfigKey。NIWSServerListClassName,DefaultClientConfigImpl。DEFAULTSEVERLISTCLASS);ServerListTniwsServerListImpl(ServerListT)ClientFactory。instantiateInstanceWithClientConfig(niwsServerListClassName,clientConfig);this。serverListImplniwsServerListImpl;if(niwsServerListImplinstanceofAbstractServerList){AbstractServerListFilterTniwsFilter((AbstractServerList)niwsServerListImpl)。getFilterImpl(clientConfig);niwsFilter。setLoadBalancerStats(getLoadBalancerStats());this。filterniwsFilter;}StringserverListUpdaterClassNameclientConfig。getPropertyAsString(CommonClientConfigKey。ServerListUpdaterClassName,DefaultClientConfigImpl。DEFAULTSERVERLISTUPDATERCLASS);this。serverListUpdater(ServerListUpdater)ClientFactory。instantiateInstanceWithClientConfig(serverListUpdaterClassName,clientConfig);restOfInit(clientConfig);}catch(Exceptione){thrownewRuntimeException(ExceptionwhileinitializingNIWSDiscoveryLoadBalancer:clientConfig。getClientName(),niwsClientConfig:clientConfig,e);}}
  在restOfInit()方法上,有一个updateListOfServers()的方法,该方法是用来获取所有的ServerList的。voidrestOfInit(IClientConfigclientConfig){booleanprimeConnectionthis。isEnablePrimingConnections();turnthisofftoavoidduplicatedasynchronousprimingdoneinBaseLoadBalancer。setServerList()this。setEnablePrimingConnections(false);enableAndInitLearnNewServersFeature();updateListOfServers();if(primeConnectionthis。getPrimeConnections()!null){this。getPrimeConnections()。primeConnections(getReachableServers());}this。setEnablePrimingConnections(primeConnection);LOGGER。info(DynamicServerListLoadBalancerforclient{}initialized:{},clientConfig。getClientName(),this。toString());}
  进一步跟踪updateListOfServers()方法的源码,最终由serverListImpl。getUpdatedListOfServers()获取所有的服务列表的,代码如下:VisibleForTestingpublicvoidupdateListOfServers(){ListTserversnewArrayListT();if(serverListImpl!null){serverList接口的实现类serversserverListImpl。getUpdatedListOfServers();LOGGER。debug(ListofServersfor{}obtainedfromDiscoveryclient:{},getIdentifier(),servers);if(filter!null){serversfilter。getFilteredListOfServers(servers);LOGGER。debug(FilteredListofServersfor{}obtainedfromDiscoveryclient:{},getIdentifier(),servers);}}updateAllServerList(servers);}
  而serverListImpl是ServerList接口的具体实现类。跟踪代码,ServerList的实现类为DiscoveryEnabledNIWSServerList,在ribboneureka。jar的com。netflix。niws。loadbalancer下。其中DiscoveryEnabledNIWSServerList有getInitialListOfServers()和getUpdatedListOfServers()方法,具体代码如下:OverridepublicListDiscoveryEnabledServergetInitialListOfServers(){returnobtainServersViaDiscovery();}OverridepublicListDiscoveryEnabledServergetUpdatedListOfServers(){returnobtainServersViaDiscovery();}
  继续跟踪源码,obtainServersViaDiscovery(),是根据eurekaClientProvider。get()来回去EurekaClient,再根据EurekaClient来获取注册列表信息,代码如下:privateListDiscoveryEnabledServerobtainServersViaDiscovery(){ListDiscoveryEnabledServerserverListnewArrayListDiscoveryEnabledServer();if(eurekaClientProvidernulleurekaClientProvider。get()null){logger。warn(EurekaClienthasnotbeeninitializedyet,returninganemptylist);returnnewArrayListDiscoveryEnabledServer();}EurekaClienteurekaClienteurekaClientProvider。get();if(vipAddresses!null){for(StringvipAddress:vipAddresses。split(,)){iftargetRegionisnull,itwillbeinterpretedasthesameregionofclientListInstanceInfolistOfInstanceInfoeurekaClient。getInstancesByVipAddress(vipAddress,isSecure,targetRegion);for(InstanceInfoii:listOfInstanceInfo){if(ii。getStatus()。equals(InstanceStatus。UP)){if(shouldUseOverridePort){if(logger。isDebugEnabled()){logger。debug(Overridingportonclientname:clientNametooverridePort);}copyisnecessarysincetheInstanceInfobuilderjustusestheoriginalreference,andwedontwanttocorrupttheglobaleurekacopyoftheobjectwhichmaybeusedbyotherclientsinoursystemInstanceInfocopynewInstanceInfo(ii);if(isSecure){iinewInstanceInfo。Builder(copy)。setSecurePort(overridePort)。build();}else{iinewInstanceInfo。Builder(copy)。setPort(overridePort)。build();}}DiscoveryEnabledServerdesnewDiscoveryEnabledServer(ii,isSecure,shouldUseIpAddr);des。setZone(DiscoveryClient。getZone(ii));serverList。add(des);}}if(serverList。size()0prioritizeVipAddressBasedServers){break;ifthecurrentvipAddresshasservers,wedontusesubsequentvipAddressbasedservers}}}returnserverList;}
  其中eurekaClientProvider的实现类是LegacyEurekaClientProvider,它是一个获取eurekaClient类,通过静态的方法去获取eurekaClient,其代码如下:classLegacyEurekaClientProviderimplementsProviderEurekaClient{privatevolatileEurekaClienteurekaClient;OverridepublicsynchronizedEurekaClientget(){if(eurekaClientnull){eurekaClientDiscoveryManager。getInstance()。getDiscoveryClient();}returneurekaClient;}}
  EurekaClient的实现类为DiscoveryClient,在之前已经分析了它具有服务注册、获取服务注册列表等的全部功能。
  由此可见,负载均衡器是从EurekaClient获取服务信息,并根据IRule去路由,并且根据IPing去判断服务的可用性。
  那么现在还有个问题,负载均衡器多久一次去获取一次从EurekaClient获取注册信息呢。
  在BaseLoadBalancer类下,BaseLoadBalancer的构造函数,该构造函数开启了一个PingTask任务,代码如下:publicBaseLoadBalancer(Stringname,IRulerule,LoadBalancerStatsstats,IPingping,IPingStrategypingStrategy){。。。代码省略setupPingTask();。。。代码省略}
  setupPingTask()的具体代码逻辑,它开启了ShutdownEnabledTimer执行PingTask任务,在默认情况下pingIntervalSeconds为10,即每10秒钟,想EurekaClient发送一次ping。voidsetupPingTask(){if(canSkipPing()){return;}if(lbTimer!null){lbTimer。cancel();}lbTimernewShutdownEnabledTimer(NFLoadBalancerPingTimername,true);lbTimer。schedule(newPingTask(),0,pingIntervalSeconds1000);forceQuickPing();}
  PingTask源码,即new一个Pinger对象,并执行runPinger()方法。classPingTaskextendsTimerTask{publicvoidrun(){try{newPinger(pingStrategy)。runPinger();}catch(Exceptione){logger。error(LoadBalancer〔{}〕:Errorpinging,name,e);}}}
  查看Pinger的runPinger()方法,最终根据pingerStrategy。pingServers(ping,allServers)来获取服务的可用性,如果该返回结果,如之前相同,则不去向EurekaClient获取注册列表,如果不同则通知ServerStatusChangeListener或者changeListeners发生了改变,进行更新或者重新拉取。publicvoidrunPinger()throwsException{if(!pingInProgress。compareAndSet(false,true)){return;Pinginprogressnothingtodo}weareinwegettoPingServer〔〕allServersnull;boolean〔〕resultsnull;LockallLocknull;LockupLocknull;try{ThereadLockshouldbefreeunlessanaddServeroperationisgoingon。。。allLockallServerLock。readLock();allLock。lock();allServersallServerList。toArray(newServer〔allServerList。size()〕);allLock。unlock();intnumCandidatesallServers。length;resultspingerStrategy。pingServers(ping,allServers);finalListServernewUpListnewArrayListServer();finalListServerchangedServersnewArrayListServer();for(inti0;inumCandidates;i){booleanisAliveresults〔i〕;ServersvrallServers〔i〕;booleanoldIsAlivesvr。isAlive();svr。setAlive(isAlive);if(oldIsAlive!isAlive){changedServers。add(svr);logger。debug(LoadBalancer〔{}〕:Server〔{}〕statuschangedto{},name,svr。getId(),(isAlive?ALIVE:DEAD));}if(isAlive){newUpList。add(svr);}}upLockupServerLock。writeLock();upLock。lock();upServerListnewUpList;upLock。unlock();notifyServerStatusChangeListener(changedServers);}finally{pingInProgress。set(false);}}
  由此可见,LoadBalancerClient是在初始化的时候,会向Eureka回去服务注册列表,并且向通过10s一次向EurekaClient发送ping,来判断服务的可用性,如果服务的可用性发生了改变或者服务数量和之前的不一致,则更新或者重新拉取。LoadBalancerClient有了这些服务注册列表,就可以根据具体的IRule来进行负载均衡。RestTemplate是如何和Ribbon结合的
  最后,回答问题的本质,为什么在RestTemplate加一个LoadBalance注解就可可以开启负载均衡呢?LoadBalancedRestTemplaterestTemplate(){returnnewRestTemplate();}
  全局搜索ctrshiftfLoadBalanced有哪些类用到了LoadBalanced有哪些类用到了,发现LoadBalancerAutoConfiguration类,即LoadBalancer自动配置类。ConfigurationConditionalOnClass(RestTemplate。class)ConditionalOnBean(LoadBalancerClient。class)EnableConfigurationProperties(LoadBalancerRetryProperties。class)publicclassLoadBalancerAutoConfiguration{LoadBalancedAutowired(requiredfalse)privateListRestTemplaterestTemplatesCollections。emptyList();}BeanpublicSmartInitializingSingletonloadBalancedRestTemplateInitializer(finalListRestTemplateCustomizercustomizers){returnnewSmartInitializingSingleton(){OverridepublicvoidafterSingletonsInstantiated(){for(RestTemplaterestTemplate:LoadBalancerAutoConfiguration。this。restTemplates){for(RestTemplateCustomizercustomizer:customizers){customizer。customize(restTemplate);}}}};}ConfigurationConditionalOnMissingClass(org。springframework。retry。support。RetryTemplate)staticclassLoadBalancerInterceptorConfig{BeanpublicLoadBalancerInterceptorribbonInterceptor(LoadBalancerClientloadBalancerClient,LoadBalancerRequestFactoryrequestFactory){returnnewLoadBalancerInterceptor(loadBalancerClient,requestFactory);}BeanConditionalOnMissingBeanpublicRestTemplateCustomizerrestTemplateCustomizer(finalLoadBalancerInterceptorloadBalancerInterceptor){returnnewRestTemplateCustomizer(){Overridepublicvoidcustomize(RestTemplaterestTemplate){ListClientHttpRequestInterceptorlistnewArrayList(restTemplate。getInterceptors());list。add(loadBalancerInterceptor);restTemplate。setInterceptors(list);}};}}}
  在该类中,首先维护了一个被LoadBalanced修饰的RestTemplate对象的List,在初始化的过程中,通过调用customizer。customize(restTemplate)方法来给RestTemplate增加拦截器LoadBalancerInterceptor。
  而LoadBalancerInterceptor,用于实时拦截,在LoadBalancerInterceptor这里实现来负载均衡。LoadBalancerInterceptor的拦截方法如下:OverridepublicClientHttpResponseintercept(finalHttpRequestrequest,finalbyte〔〕body,finalClientHttpRequestExecutionexecution)throwsIOException{finalURIoriginalUrirequest。getURI();StringserviceNameoriginalUri。getHost();Assert。state(serviceName!null,RequestURIdoesnotcontainavalidhostname:originalUri);returnthis。loadBalancer。execute(serviceName,requestFactory。createRequest(request,body,execution));}总结
  综上所述,Ribbon的负载均衡,主要通过LoadBalancerClient来实现的,而LoadBalancerClient具体交给了ILoadBalancer来处理,ILoadBalancer通过配置IRule、IPing等信息,并向EurekaClient获取注册列表的信息,并默认10秒一次向EurekaClient发送ping,进而检查是否更新服务列表,最后,得到注册列表后,ILoadBalancer根据IRule的策略进行负载均衡。
  而RestTemplate被LoadBalance注解后,能过用负载均衡,主要是维护了一个被LoadBalance注解的RestTemplate列表,并给列表中的RestTemplate添加拦截器,进而交给负载均衡器去处理。

新春新局,扬帆再发,邢钢复产顺利出铁出钢新年新气象,邢台钢铁有限责任公司炼铁厂炼钢厂喜讯频传截止到1月21日,顺利实现出铁出钢,这对涅槃重生中的邢钢来说意义非凡。此举,标志着邢钢在精品特钢之路上,砥砺奋进,再次扬帆起航,日本人最爱小面包?铃木是第二大车企?盘点日本2022年销量排行作为一个岛国,中国民间对于日本总是称为弹丸之地,确实以中国960万平方公里的体量来看它,它37。8平方公里的面积确实不值一提。但如果把日本放到欧洲,那妥妥的是一个大国,土地面积超过首旅集团春节假期旗下餐饮业态销售收入同比增长71。99中证网讯(记者潘宇静)1月28日,记者从首旅集团获悉,2023年春节假期,首旅集团共接待游客28万人次,同比增长12。91,实现销售收入同比增长25。98。伴随着除夕夜年夜饭开启新A股明天(1月30日)大盘走势简析会以何种走势,开启兔年行情明天A股在万众期待下,就要开盘了,今天不谈是不是牛市,这和我们的实际操作没什么关系,因为你赚钱,是通过买卖实现的,不是通过牛市实现的。下面,有两个问题,需要明确关注,再来看看明天A父母是怎样毁掉孩子的好多年前,在我们村有个孩子。这个孩子的邻居是个退休的老教师,写得一手好看的毛笔字。每年的春节前,村子里的人都会拿上春联纸到老教师家里让其帮忙写春联。每个得到春联的人都会称赞几句字好机构春节假期二手房市场北热南冷,一线城市需求热度上升新京报讯(记者张晓兰)1月28日,据58安居客研究院统计数据显示,全国70城二手房春节期间日均需求热度相比1月出现明显上涨,合计上涨城市为56个,其中仅有9个二线城市和5个三线城市这个春节,有史以来最糟心的一个春节每年的春节都是祥和美好氛围,今年腊月29下午三点半,孩子小腿被开水烫伤,这个春节注定有点不一样。平时刷手机会看到烫伤相关知识,什么不能脱衣服,只能剪刀剪,什么烫伤后要立即将烫伤部位中国官制史为什么要建立中央集权制度?春秋时代的社会变革犹如急风暴雨,旧传统和新风尚旧制度和新规定旧观念和新意识,在暴风雨中混杂一起。战国时代的社会变革则犹如大浪淘沙,也就使传统社会退出了历史舞台,一个新的社会模式出现从青楼到夜总会,人们的品味直接从S档掉到了N档从事卖笑行业的人群,古往今来已经发生了很大的变化由古代的卖艺不卖身和卖身两个行业,沦落到近代只卖身不卖艺的单一行业。而且其才艺也呈断崖式下降,沦落到几乎没有门槛的地步。可谓世风日下历史上真正的纪晓岚原来是这样的!他是电视剧中无数次智斗大贪官和珅的铁齿铜牙,又是幽默风趣游戏文字的纪大烟袋。他名气很大,所以有关于他的传说很多。而历史上真实的纪晓岚果真如此吗?有人说他日御数女,是个风流才子。也有中国为什么很少拍元朝历史剧?不是不想拍,而是确实不能拍以古为镜,可知兴替。历史是厚重而又绚丽的,它承载着一代又一代人的生活轨迹,组成了人类在这片大地上生命的篇章。不过,历史始终是过去式,而时间永远都是向未来前进,不可能倒退到过去,这个
欠款122亿,贾跃亭还能走多远?传了亿次要下周回国的贾跃亭,有新消息了他创办的电动车FF公司(FaradayFuture法拉第未来)在美国融了1亿美元,给他的造车梦成功添砖加瓦。如今的贾跃亭,露面似乎只跟电动车有房贷利率又降了,还会降吗有人说当下房地产市场是买卖双方的一场博弈?本人认为答案是否定的!因为当下购房需求真的已经透支,已经没有了博弈的条件,直接一些说就是买房者主动权更大一些,为什么?因为买得起房子的已经欧盟自残,欧佩克助攻俄,拜登难力挽狂澜,欧洲或被迫与普京合作大难临头,欧盟为了制裁俄还在自残尽管不少欧盟国家通过自残行动对俄罗斯的石油实施了严厉的制裁,希望以此来卡住俄罗斯的脖子减少俄罗斯从石油销售中获得利润,进而控制俄乌战争的烈度。但眼看福建卖花生油小贩,21岁逃往印尼,华丽转身,雄踞华人首富头条创作挑战赛在中国最津津乐道的白手起家故事,莫过于创办阿里巴巴的马老板,他从清寒老师成为中国首富。而在印尼,也有一位传奇,他叫林绍良,他曾经只是路边卖花生油的小摊贩,谁知道数十年风向变了?美智库呼吁拜登转变对华态度,马斯克发声支持两岸统一据环球网报道,美外交政策协会以发布报告形式对拜登政府发出呼吁,指出中国发展对美而言是商机,应当取消对华加征关税并基于对中国的客观认知制定对华政策。中国外交部发言人毛宁对此评价指出,轻巧便携体验出色,小米投影仪mini体验报告作为一名长期在外的打工人,也曾渴望在自己的小出租屋里面拥有一间影音房,劳累一天下班回来后躺在椅子上看看电影,刷刷剧,周末也可以一个人窝在家里唱唱歌或约三两好友一块放肆一次。就这看似被曾志伟庆生聚会亲吻的26岁辣模发声怀疑许错愿望69岁香港资深艺人曾志伟,前几日出席一场庆生聚会,期间先是陪同一名年轻女模吹蜡烛,接着嘴对嘴亲吻这位26岁马来西亚辣模黎峇拉(Lebara),引发外界讨论。对此,曾志伟率先出面回应王思聪疑深夜赌博!与众富豪打麻将流水超千万,好友喊话没人敢管王思聪疑深夜赌博!与众富豪打麻将流水超千万,好友喊话没人敢管,惊爆中国富豪与17岁日未成年女星发生关系!花钱找人女孩未成年,王思聪最近躺枪拼拼。王思聪疑似聚众赌博惹争议!为何情史丰你可能知道邓文迪,但你可能没有真正看懂过她的上位法则男人征服世界,女人征服男人。这句话用在邓文迪身上再合适不过了。她精如猎人,只要瞄准目标,没有她征服不了的猎物,哪怕对方是山中大王,她依旧能一招命中。崇尚要么狠,要么忍。因为这两个极人风流情史混乱,公开场合遛鸟的王大陆是真敢玩啊文话多多娱乐圈是一个最会玩文字游戏的存在,这不,当初声称只是兄妹关系的王大陆和蔡卓宜,现在,终于知道真相了。王大陆团队在官网宣布他会加盟密逃4,他的绯闻女友蔡卓宜就在机场出现时,被长大后才懂,陆展元为何不选李莫愁,而选何浣君以前读神雕侠侣时,一直不明白陆展元为何不选李莫愁,而选何浣君。曾经一度认为,陆展元是个渣男,然而随着年纪渐大,却慢慢理解了陆展元。其实很多人对于李莫愁这个人物,是抱有同情心,她是很
友情链接:快好找快生活快百科快传网中准网文好找聚热点快软网