public <T> T getInstance(String name, Class<T> type) { AnnotationConfigApplicationContext context = getContext(name); if (BeanFactoryUtils.beanNamesForTypeIncludingAncestors(context, type).length > 0) { return context.getBean(type);返回bean } return null; }
获取到ILoadBalancer
实现,我们就可以调用其chooseServer
获得一个服务实例,进行请求了。
ILoadBalancer userLoadBalancer = clientFactory.getLoadBalancer("user"); Server server = userLoadBalancer.chooseServer("default")
3.4 (使用) LoadBalancerClient
LoadBalancerClient封装了SpringClientFactory, 作为负载均衡器客户端,被广泛使用。这个类才是SC-Ribbon的真正负载均衡客户端的入口。
提供了三个方法:
- 选择服务实例方法;
- 执行请求方法
- 重构uri方法。
每个方法都是与负载均衡有关
ServiceInstance choose(String serviceId); <T> T execute(String serviceId, LoadBalancerRequest<T> request) throws IOException; URI reconstructURI(ServiceInstance instance, URI original);
LoadBalancerClient作为负载均衡客户端。他的能力完全是建立在以上所有组件的共同努力下实现的。
public class MyClass { @Autowired private LoadBalancerClient loadBalancer; public void doStuff() { ServiceInstance instance = loadBalancer.choose("stores"); URI storesUri = URI.create(String.format("http://%s:%s", instance.getHost(), instance.getPort())); // ... do something with the URI } }
3.SC-Ribbon与eureka一起使用又发生了什么
1.配置层面:
当SpringCloudRibbon
与Eureka
一起使用时,会使用@RibbonClients
为所有的服务的负载均衡替换一些默认组件(更换组合套件)
@Configuration @EnableConfigurationProperties @ConditionalOnClass(DiscoveryEnabledNIWSServerList.class) @ConditionalOnBean(SpringClientFactory.class) @ConditionalOnProperty(value = "ribbon.eureka.enabled", matchIfMissing = true) @AutoConfigureAfter(RibbonAutoConfiguration.class) @RibbonClients(defaultConfiguration = EurekaRibbonClientConfiguration.class) public class RibbonEurekaAutoConfiguration { } ---------------------------- @Configuration @CommonsLog public class EurekaRibbonClientConfiguration { @Bean @ConditionalOnMissingBean public IPing ribbonPing(IClientConfig config) { NIWSDiscoveryPing ping = new NIWSDiscoveryPing();// ping.initWithNiwsConfig(config); return ping; } @Bean @ConditionalOnMissingBean public ServerList<?> ribbonServerList(IClientConfig config) { DiscoveryEnabledNIWSServerList discoveryServerList = new DiscoveryEnabledNIWSServerList( config); DomainExtractingServerList serverList = new DomainExtractingServerList( discoveryServerList, config, this.approximateZoneFromHostname); return serverList; } }
- IPing: 使用NIWSDiscoveryPing这个实现
- ServerList:使用了
DomainExtractingServerList
。DomainExtractingServerList
代理了DiscoveryEnabledNIWSServerList
。DiscoveryEnabledNIWSServerList
存储的服务列表都从EurekaClient
本地缓存里取到的。(取操作是PollingServerListUpdater
,定时执行的)
public class DiscoveryEnabledNIWSServerList extends AbstractServerList<DiscoveryEnabledServer>{ private List<DiscoveryEnabledServer> obtainServersViaDiscovery() { EurekaClient eurekaClient = eurekaClientProvider.get(); List<InstanceInfo> listOfInstanceInfo = eurekaClient.getInstancesByVipAddress(vipAddress, isSecure, targetRegion); .... } }
2.使用层面:
没啥变化,就是使用LoadBalancerClient
来使用负载均衡获取一个Server。
4.Resttemplate 如何具有负载均衡能力
Resttemplate 具有负载均衡能力,其本质还是通过使用LoadBalancerClient
来实现。
如何实现呢?
这就涉及到两个知识点:
Resttemplate
相关体系:@LoadBalanced
注解。
Resttemplate
是有拦截器的概念的 。也就是说在真正发起请求之前,会走一些拦截器。这就给负载均衡选择一个Server
提供了机会。
@LoadBalanced
注解就是给其修饰的Resttemplate
实例,注入LoadBalancerInterceptor
拦截器。此拦截器就是通过LoadBalancerClient
来实现了负载均衡
public class LoadBalancerInterceptor implements ClientHttpRequestInterceptor { private LoadBalancerClient loadBalancer; ... }
具体可阅读我的其他文章
发送http请求(2):RestTemplate发送http请求
@LoadBalanced注解的RestTemplate拥有负载均衡的能力
5.总结
文本从介绍负载均衡的几个组件开始,由底层讲到了Resttemplate
原理。打开了Resttemplate
发起负载均衡请求的黑盒。顺着这条线,只要仔细研读各个部分的知识点。
你会感叹开源框架的大厦的建立,为我们省去了多少开发工作。
我们不应该是停留在使用的阶段,还应该深入去了解底层框架的原理,这样你才会在大厦之上更进一层。
参考链接:
如果本文任何错误,请批评指教,不胜感激 !
如果文章哪些点不懂,可以联系我交流学习!