Ribbon- 学习源码解析
标记RestTemplate对象
当我们使用@LoadBalanced标签对我们调用微服务提供方接口的RestTemplate类做注解的时候。
这一步就是其实在标签里什么都没做,只是在spring容器中的RestTemplate对象打了一个标记。
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
Spring 容器启动时找相关的spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.cloud.netflix.ribbon.RibbonAutoConfiguration
Spring自动装配了RibbonAutoConfiguration
找到这个类还做了@AutoConfigureBefore的注解并且包含了LoadBalancerAutoConfiguration.class
@Configuration
@Conditional({RibbonAutoConfiguration.RibbonClassesConditions.class})
@RibbonClients
@AutoConfigureAfter(
name = {"org.springframework.cloud.netflix.eureka.EurekaClientAutoConfiguration"}
)
@AutoConfigureBefore({LoadBalancerAutoConfiguration.class, AsyncLoadBalancerAutoConfiguration.class})
@EnableConfigurationProperties({RibbonEagerLoadProperties.class, ServerIntrospectorProperties.class})
public class RibbonAutoConfiguration {
@Autowired(
required = false
)
private List<RibbonClientSpecification> configurations = new ArrayList();
@Autowired
private RibbonEagerLoadProperties ribbonEagerLoadProperties;
public RibbonAutoConfiguration() {
}
转到LoadBalancerAutoConfiguration
这个类中有@ConditionalOnClass(RestTemplate.class) 表示判断当前classpath下是否存在指定类RestTemplate.class,若存在则将当前被注解的配置LoadBalancerAutoConfiguration装载入spring容器
当然他还有@ConditionalOnBean(LoadBalancerClient.class) 表示判断当前context下是否存在指定beanLoadBalancerClient.class,若有则将当前被注解的配置LoadBalancerAutoConfiguration装载入spring容器
@Configuration
@ConditionalOnClass({RestTemplate.class})
@ConditionalOnBean({LoadBalancerClient.class})
@EnableConfigurationProperties({LoadBalancerRetryProperties.class})
public class LoadBalancerAutoConfiguration {
@LoadBalanced
@Autowired(
required = false
)
private List<RestTemplate> restTemplates = Collections.emptyList();
@Autowired(
required = false
)
执行封装新的interceptor
下面就是关键方法,在容器中找到所有restTemplate bean,获取它上面的所有Interceptor。
然后将我们的loadBalancerInterceptor给加进去。
当然,在这个类中还加进去了一个叫做RetryLoadBalancerInterceptor的intercepotr
这两段代码分别在两个不同的静态代码块里面
RetryInterceptorAutoConfiguration和LoadBalancerInterceptorConfig
@Bean
@ConditionalOnMissingBean
public RestTemplateCustomizer restTemplateCustomizer(final LoadBalancerInterceptor loadBalancerInterceptor) {
return (restTemplate) -> {
List<ClientHttpRequestInterceptor> list = new ArrayList(restTemplate.getInterceptors());
list.add(loadBalancerInterceptor);
restTemplate.setInterceptors(list);
};
}
@Bean
@ConditionalOnMissingBean
public RestTemplateCustomizer restTemplateCustomizer(final RetryLoadBalancerInterceptor loadBalancerInterceptor) {
return (restTemplate) -> {
List<ClientHttpRequestInterceptor> list = new ArrayList(restTemplate.getInterceptors());
list.add(loadBalancerInterceptor);
restTemplate.setInterceptors(list);
};
}
当restTemplate开始请求
product = restTemplate.getForObject("http://service-product/product/" + id,Product.class);
-
不是马上执行API调用,而是会走到拦截器中,其中一个就是LoadBalancerInterceptor
-
在LoadBalancerInterceptor.intercept里面使用LoadBalancerClient执行loadBalancer.execute
return (ClientHttpResponse)this.loadBalancer.execute(serviceName, this.requestFactory.createRequest(request, body, execution));
-
调转到RibbonLoadBalancerClient,在execute方法中通过serviceID获得一个ILoadBalancer (负载均衡器)
ILoadBalancer loadBalancer = this.getLoadBalancer(serviceId);
-
传入ILoadBalancer和hint执行getServer获取到真正带执行的server, 下面显示getServer的逻辑流程
- 当ILoadBalancer不为空,将ILoadBalancer和hint对象传入BaseLoadBalancer的chooseServer方法
- 在chooseServer中先增加counter记数,
- 通过找到不同的rule的配置并传入hint通过负载均衡策略的choose方法得到server
choose方法不同负载均衡策略的实现不同,有兴趣的朋友可以去看看每个rule的策略算法是怎样的。
Server server = this.getServer(loadBalancer, hint); protected Server getServer(ILoadBalancer loadBalancer, Object hint) { return loadBalancer == null ? null : loadBalancer.chooseServer(hint != null ? hint : "default"); }
public Server chooseServer(Object key) { if (this.counter == null) { this.counter = this.createCounter(); } this.counter.increment(); if (this.rule == null) { return null; } else { try { return this.rule.choose(key); } catch (Exception var3) { logger.warn("LoadBalancer [{}]: Error choosing server for key {}", new Object[]{this.name, key, var3}); return null; } } }
-
将获得的server作为初始化参数创建ribbonServer
RibbonLoadBalancerClient.RibbonServer ribbonServer = new RibbonLoadBalancerClient.RibbonServer(serviceId, server, this.isSecure(server, serviceId), this.serverIntrospector(serviceId).getMetadata(server));
-
传入ribbonServer执行真正的execute
public <T> T execute(String serviceId, ServiceInstance serviceInstance, LoadBalancerRequest<T> request) throws IOException { Server server = null; if (serviceInstance instanceof RibbonLoadBalancerClient.RibbonServer) { server = ((RibbonLoadBalancerClient.RibbonServer)serviceInstance).getServer(); } if (server == null) { throw new IllegalStateException("No instances available for " + serviceId); } else { RibbonLoadBalancerContext context = this.clientFactory.getLoadBalancerContext(serviceId); RibbonStatsRecorder statsRecorder = new RibbonStatsRecorder(context, server); try { T returnVal = request.apply(serviceInstance); statsRecorder.recordStats(returnVal); return returnVal; } catch (IOException var8) { statsRecorder.recordStats(var8); throw var8; } catch (Exception var9) { statsRecorder.recordStats(var9); ReflectionUtils.rethrowRuntimeException(var9); return null; } } }
附录
注解ConditionalOnXXX
@ConditionalOnBean // 当给定的在bean存在时,则实例化当前Bean
@ConditionalOnMissingBean // 当给定的在bean不存在时,则实例化当前Bean
@ConditionalOnClass // 当给定的类名在类路径上存在,则实例化当前Bean
@ConditionalOnMissingClass // 当给定的类名在类路径上不存在,则实例化当前Bean