一、簡介
使用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就清楚了,跟之前的負載均衡器結合起來了