spring-cloud 源码解析-Ribbon

参考文档

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