什么是Ribbon
Ribbon是一个提供在客户端的负载均衡的组件,相对于nginx会较轻量级。Ribbon的本质其实就是一个拦截器。相信大家都知道在使用Ribbon的时候,会和RestTemplate一起使用,在使用RestTempplate的时候,但此时的URL是一个htpp://servername/method的一个形式,所以Ribbon会在调用前,进行拦截,将Url解析成,http://ip+port的的形式,然后在进行负载均衡相关算法来分发HTTP请求。
- 解析基于配置中的服务器列表
- 基于负载均衡算法来分发HTTP请求
刨析Ribbon源码
我们来看这样一段代码
@Controller
public class UserController {
@Autowired
RestTemplate restTemplate;
@Bean
@LoadBalanced
public RestTemplate restTemplate(RestTemplateBuilder restTemplateBuilder){
return restTemplateBuilder.build();
}
@Autowired
LoadBalancerClient loadBalancerClient;
@GetMapping("/user/{id}")
public String findById(@PathVariable("id")int id){
ServiceInstance serviceInstance=loadBalancerClient.choose("spring-cloud-order-service");
String url=String.format("http://%s:%s",serviceInstance.getHost(),serviceInstance.getPort()+"/orders");
return restTemplate.getForObject(url,String.class);
}
}
由此可以看出,与常规使用restTemplate进行正常的http调用,这里只多了一个注解@LoadBalanced,那就从这个注解开始瞅瞅它的真面目。@LoadBalanced的源码是这样的:
package org.springframework.cloud.client.loadbalancer;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.beans.factory.annotation.Qualifier;
/**
* Annotation to mark a RestTemplate or WebClient bean to be configured to use a
* LoadBalancerClient.
* @author Spencer Gibb
*/
@Target({
ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Qualifier
public @interface LoadBalanced {
}
在上面的源码中我们看到了@Qualifier这个注解了,这个注解表示一个标记的含义,由此可以得出,@loadBalanced是给RestTepmlate做了一个标记,那么我们来具体看看这个标记做了什么事。我们先搜索到LoadBalancerAutoConfiguration 这个类
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(RestTemplate.class)
@ConditionalOnBean(LoadBalancerClient.class)
@EnableConfigurationProperties(LoadBalancerRetryProperties.class)
public class LoadBalancerAutoConfiguration {
//自动扫描加了@LoadBalanced标注的类,进行注入
@LoadBalanced
@Autowired(required = false)
private List<RestTemplate> restTemplates = Collections.emptyList();
@Autowired(required = false)
private List<LoadBalancerRequestTransformer> transformers = Collections.emptyList();
@Bean
public SmartInitializingSingleton loadBalancedRestTemplateInitializerDeprecated(
final ObjectProvider<List<RestTemplateCustomizer>> restTemplateCustomizers) {
return () -> restTemplateCustomizers.ifAvailable(customizers -> {
for (RestTemplate restTemplate : LoadBalancerAutoConfiguration.this.restTemplates) {
for (RestTemplateCustomizer customizer : customizers) {
customizer.customize(restTemplate);
}
}
});
}
@Bean
@ConditionalOnMissingBean
public LoadBalancerRequestFactory loadBalancerRequestFactory(
LoadBalancerClient loadBalancerClient) {
return new LoadBalancerRequestFactory(loadBalancerClient, this.transformers);
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnMissingClass("org.springframework.retry.support.RetryTemplate")
static class LoadBalancerInterceptorConfig {
@Bean
public LoadBalancerInterceptor ribbonInterceptor(
LoadBalancerClient loadBalancerClient,
LoadBalancerRequestFactory requestFactory) {
return new LoadBalancerInterceptor(loadBalancerClient, requestFactory);
}
@Bean
@ConditionalOnMissingBean
public RestTemplateCustomizer restTemplateCustomizer(
final LoadBalancerInterceptor loadBalancerInterceptor) {
return restTemplate -> {
List<ClientHttpRequestInterceptor> list = new ArrayList<>(
restTemplate.getInterceptors());
list.add(loadBalancerInterceptor);
restTemplate.setInterceptors<