一、简介
使用ribbon,一般都是和springcloud结合使用,springcloud提供了胶水代码来整合ribbon。
二、接口
ServiceInstanceChooser该接口只有一个方法:
public interface ServiceInstanceChooser {
/**
* Choose a ServiceInstance from the LoadBalancer for the specified service
* @param serviceId the service id to look up the LoadBalancer
* @return a ServiceInstance that matches the serviceId
*/
ServiceInstance choose(String serviceId);
}
其实现类如下:
我们可以看到好多Retry开头的,这些类的实例会被自动注入,如果class路径发现org.springframework.retry.support.RetryTemplate的话。
也就是说,默认情况下,并没有开启retry功能。如果需要开启retry机制,需要引入以下配置:
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
</dependency>
这里对于retry相关的不再多写,详细请参考重试。
那么,默认的就只有一个类了,就是RibbonLoadBalancerClient。
三、实现
这里看一下如何实现choose的:
- 首先对于每个serviceId,spring会创建一个单独的ILoadBalancer。
- 之后调用ILoadBalancer.chooseServer(“default”),这里就对应到了负载均衡器的ZoneAwareLoadBalancer.choose流程。
四、与RestTemplate整合
参照[结合ribbonLoadBalanced]的部分,整个调用过程如下:
可以看到,调用链还是比较长的,最终会调用到ILoadBalancer,实现负载均衡。
五、与Feign整合
从spring-cloud-netflix-core/META-INF/sping.factories可以看到这个自动注入类:FeignRibbonClientAutoConfiguration,它的condition如下:
@ConditionalOnClass({ ILoadBalancer.class, Feign.class })
也就是说,如果classpath存在ribbon的依赖和Feign的依赖,将启用该配置。
那么注入的feign使用的http客户端是哪个?
1.HttpURLConnection的
@Bean
@ConditionalOnMissingBean
public Client feignClient(CachingSpringLoadBalancerFactory cachingFactory,
SpringClientFactory clientFactory) {
return new LoadBalancerFeignClient(new Client.Default(null, null),
cachingFactory, clientFactory);
}
2.httpclient的
@Configuration
@ConditionalOnClass(ApacheHttpClient.class)
@ConditionalOnProperty(value = "feign.httpclient.enabled", matchIfMissing = true)
protected static class HttpClientFeignLoadBalancedConfiguration {
@Autowired(required = false)
private HttpClient httpClient;
@Bean
@ConditionalOnMissingBean(Client.class)
public Client feignClient(CachingSpringLoadBalancerFactory cachingFactory,
SpringClientFactory clientFactory) {
ApacheHttpClient delegate;
if (this.httpClient != null) {
delegate = new ApacheHttpClient(this.httpClient);
}
else {
delegate = new ApacheHttpClient();
}
return new LoadBalancerFeignClient(delegate, cachingFactory, clientFactory);
}
}
3.okhttp的
@Configuration
@ConditionalOnClass(OkHttpClient.class)
@ConditionalOnProperty(value = "feign.okhttp.enabled", matchIfMissing = true)
protected static class OkHttpFeignLoadBalancedConfiguration {
@Autowired(required = false)
private okhttp3.OkHttpClient okHttpClient;
@Bean
@ConditionalOnMissingBean(Client.class)
public Client feignClient(CachingSpringLoadBalancerFactory cachingFactory,
SpringClientFactory clientFactory) {
OkHttpClient delegate;
if (this.okHttpClient != null) {
delegate = new OkHttpClient(this.okHttpClient);
}
else {
delegate = new OkHttpClient();
}
return new LoadBalancerFeignClient(delegate, cachingFactory, clientFactory);
}
}
httpclient和okhttp都有static修饰,那么就会比HttpURLConnection先加载。
而httpclient和okhttp取决于pom里依赖了那个jar,例如依赖feign-okhttp则为okhttp:
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-okhttp</artifactId>
</dependency>
依赖feign-httpclient则为httpclient:
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-httpclient</artifactId>
</dependency>
无论用哪个http客户端,可以看到,最终都传给了LoadBalancerFeignClient,该类最终会调用到ILoadBalancer的choose方法,流程如下图:
到这里看到ILoadBalancer就清楚了,跟之前的负载均衡器结合起来了