什么是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添加拦截器,进而交给负载均衡器去处理。