Ribbon
重点总结:
1、只有在 RestTemplate 中加上 @LoadBalanced Ribbon才会生效
2、消费服务会在调用生产服务时,创建 PingTask 任务,用来ping可用的 生产服务信息
3、会创建定时任务去执行 updateListOfServers(),更新服务集合
消费服务在使用 RestTemplate (加上了@LoadBalanced)调用 生产服务(集群)时的流程
Cofiguration 加载
RibbonAutoConfiguration 和 RibbonEurekaAutoConfiguration 含有注解 @RibbonClients
在加载(loadBeanDefinitionsForConfigurationClass)时,会执行到 RibbonClientConfigurationRegistrar 中的 registerBeanDefinitions 中
再判断 当含有 RibbonClients 和 RibbonClient 注解时
会根据
default.org.springframework.cloud.netflix.ribbon.RibbonAutoConfiguration.RibbonClientSpecification
default.org.springframework.cloud.netflix.ribbon.eureka.RibbonEurekaAutoConfiguration.RibbonClientSpecification
的名称注册到Spring中
RibbonAutoConfiguration 中的 Bean 加载
//上面步骤注册出来的 RibbonClientSpecification
@Autowired(required = false)
private List<RibbonClientSpecification> configurations = new ArrayList<>();
@Bean
@ConditionalOnMissingBean
public SpringClientFactory springClientFactory() {
SpringClientFactory factory = new SpringClientFactory();
factory.setConfigurations(this.configurations);
return factory;
}
//默认负载均衡 RibbonLoadBalancerClient
@Bean
@ConditionalOnMissingBean(LoadBalancerClient.class)
public LoadBalancerClient loadBalancerClient() {
return new RibbonLoadBalancerClient(springClientFactory());
}
@Bean
@ConditionalOnClass(name = "org.springframework.retry.support.RetryTemplate")
@ConditionalOnMissingBean
public LoadBalancedRetryFactory loadBalancedRetryPolicyFactory(
final SpringClientFactory clientFactory) {
return new RibbonLoadBalancedRetryFactory(clientFactory);
}
LoadBalancerAutoConfiguration 中的Bean加载
加了 @LoadBalanced 注解的 RestTemplate 会在拦截器中加入一个loadBalancerInterceptor
//只有加了 @LoadBalanced 注解的 RestTemplate 才会自动注入到 restTemplates 中
@LoadBalanced
@Autowired(required = false)
private List<RestTemplate> restTemplates = Collections.emptyList();
//SmartInitializingSingleton就是当所有的singleton的bean都初始化完了之后才会回调这个接口。不过要注意是 4.1 之后才出现的接口。
//效果就是把获得了所有的RestTemplate的定制化器集合customizers,设置到上一步的restTemplates集合中的每个RestTemplate里面
//到这一步,工程中所有的加了@LoadBalanced的RestTemplate里面的拦截器都加上了LoadBalancerInterceptor。
@Bean
public SmartInitializingSingleton loadBalancedRestTemplateInitializerDeprecated(
final ObjectProvider<List<RestTemplateCustomizer>> restTemplateCustomizers) {
return () -> restTemplateCustomizers.ifAvailable(customizers -> {
//当 restTemplates 不为空时,会在RestTemplate 的 拦截器中加入一个loadBalancerInterceptor
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);
}
@Bean
public LoadBalancerInterceptor loadBalancerInterceptor(
LoadBalancerClient loadBalancerClient,
LoadBalancerRequestFactory requestFactory) {
return new LoadBalancerInterceptor(loadBalancerClient, requestFactory);
}
//向 RestTemplate 添加了一个请求拦截器 LoadBalancerInterceptor
@Bean
@ConditionalOnMissingBean
public RestTemplateCustomizer restTemplateCustomizer(
final LoadBalancerInterceptor loadBalancerInterceptor) {
return restTemplate -> {
List<ClientHttpRequestInterceptor> list = new ArrayList<>(
restTemplate.getInterceptors());
list.add(loadBalancerInterceptor);
restTemplate.setInterceptors(list);
};
}
HttpClientRibbonConfiguration 中的Bean加载
@Bean
@ConditionalOnMissingBean(AbstractLoadBalancerAwareClient.class)
@ConditionalOnMissingClass("org.springframework.retry.support.RetryTemplate")
public RibbonLoadBalancingHttpClient ribbonLoadBalancingHttpClient(
IClientConfig config, ServerIntrospector serverIntrospector,
ILoadBalancer loadBalancer, RetryHandler retryHandler,
CloseableHttpClient httpClient) {
RibbonLoadBalancingHttpClient client = new RibbonLoadBalancingHttpClient(
httpClient, config, serverIntrospector);
client.setLoadBalancer(loadBalancer);
client.setRetryHandler(retryHandler);
Monitors.registerObject("Client_" + this.name, client);
return client;
}
@Bean
@ConditionalOnMissingBean(HttpClientConnectionManager.class)
public HttpClientConnectionManager httpClientConnectionManager(
IClientConfig config,
ApacheHttpClientConnectionManagerFactory connectionManagerFactory) {
RibbonProperties ribbon = RibbonProperties.from(config);
int maxTotalConnections = ribbon.maxTotalConnections();
int maxConnectionsPerHost = ribbon.maxConnectionsPerHost();
int timerRepeat = ribbon.connectionCleanerRepeatInterval();
long timeToLive = ribbon.poolKeepAliveTime();
TimeUnit ttlUnit = ribbon.getPoolKeepAliveTimeUnits();
final HttpClientConnectionManager connectionManager = connectionManagerFactory
.newConnectionManager(false, maxTotalConnections,
maxConnectionsPerHost, timeToLive, ttlUnit, registryBuilder);
//此处会创建定时任务,用来关闭过期连接
this.connectionManagerTimer.schedule(new TimerTask() {
@Override
public void run() {
connectionManager.closeExpiredConnections();
}
}, 30000, timerRepeat);
return connectionManager;
}
RibbonClientConfiguration中的Bean加载
@Bean
@ConditionalOnMissingBean
public ILoadBalancer ribbonLoadBalancer(IClientConfig config,
ServerList<Server> serverList, ServerListFilter<Server> serverListFilter,
IRule rule, IPing ping, ServerListUpdater serverListUpdater) {
if (this.propertiesFactory.isSet(ILoadBalancer.class, name)) {
return this.propertiesFactory.get(ILoadBalancer.class, config, name);
}
return new ZoneAwareLoadBalancer<>(config, rule, ping, serverList,
serverListFilter, serverListUpdater);
}
@Bean
@ConditionalOnMissingBean
public IRule ribbonRule(IClientConfig config) {
if (this.propertiesFactory.isSet(IRule.class, name)) {
return this.propertiesFactory.get(IRule.class, config, name);
}
ZoneAvoidanceRule rule = new ZoneAvoidanceRule();
rule.initWithNiwsConfig(config);
return rule;
}
@Bean
@ConditionalOnMissingBean
public IPing ribbonPing(IClientConfig config) {
if (this.propertiesFactory.isSet(IPing.class, name)) {
return this.propertiesFactory.get(IPing.class, config, name);
}
return new DummyPing();
}
EurekaRibbonClientConfiguration 中的Bean加载
@Bean
@ConditionalOnMissingBean
public IPing ribbonPing(IClientConfig config) {
if (this.propertiesFactory.isSet(IPing.class, serviceId)) {
return this.propertiesFactory.get(IPing.class, config, serviceId);
}
NIWSDiscoveryPing ping = new NIWSDiscoveryPing();
ping.initWithNiwsConfig(config);
return ping;
}
@Bean
@ConditionalOnMissingBean
public ServerList<?> ribbonServerList(IClientConfig config,
Provider<EurekaClient> eurekaClientProvider) {
if (this.propertiesFactory.isSet(ServerList.class, serviceId)) {
return this.propertiesFactory.get(ServerList.class, config, serviceId);
}
Discov