【源码】Spring Cloud —— Ribbon 1 RibbonClientConfigurationRegistrar LoadBalancerClient 相关

前言

Ribbon 是管理 HTTPTCP 服务客户端的 负载均衡器,作为 Spring Cloud负载均衡 机制的实现,它可以与 OpenFeignRestTemplate 无缝对接,让二者都具有 负载均衡 的能力

类似于 OpenFeign 的实现,Spring Cloud 为每一个 RibbonClient 维护了独立的 上下文,这些上下文由 SpringClientFactory 来管理

关于 OpenFeign 的源码解析传送门:

【源码】Spring Cloud —— OpenFeign 1 FeignClientsRegistrar FeignClientSpecification 等

版本

Spring Cloud Netflix 版本:2.2.3.RELEASE

RibbonClientConfigurationRegistrar

一般地,RibbonClient 由注解 @RibbonClient 声明

@Configuration(proxyBeanMethods = false)
@Import(RibbonClientConfigurationRegistrar.class)
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RibbonClient {

	// name
	String value() default "";

	// 名称
	String name() default "";

	// 自定义地配置类
	Class<?>[] configuration() default {};

}

可以看到引入了 RibbonClientConfigurationRegistrar

类比于 FeignClientsRegistrarRibbonClientConfigurationRegistrar 也是一个 ImportBeanDefinitionRegistrar,为配置了注册了对应 RibbonClientSpecificationBeanDefinition,源码如下:

	public void registerBeanDefinitions(AnnotationMetadata metadata,
			BeanDefinitionRegistry registry) {

		/**
		 * RibbonClients 注解解析
		 * 遍历注册所有 RibbonClient 配置类的 BD 
		 */
		Map<String, Object> attrs = metadata
				.getAnnotationAttributes(RibbonClients.class.getName(), true);
		if (attrs != null && attrs.containsKey("value")) {
			AnnotationAttributes[] clients = (AnnotationAttributes[]) attrs.get("value");
			for (AnnotationAttributes client : clients) {
				registerClientConfiguration(registry, getClientName(client),
						client.get("configuration"));
			}
		}
		
		// 全局默认配置
		if (attrs != null && attrs.containsKey("defaultConfiguration")) {
			String name;
			if (metadata.hasEnclosingClass()) {
				name = "default." + metadata.getEnclosingClassName();
			}
			else {
				name = "default." + metadata.getClassName();
			}
			registerClientConfiguration(registry, name,
					attrs.get("defaultConfiguration"));
		}
		
		// 单个 RibbonClient 的解析,注册对应配置类的 BD
		Map<String, Object> client = metadata
				.getAnnotationAttributes(RibbonClient.class.getName(), true);
		String name = getClientName(client);
		if (name != null) {
			registerClientConfiguration(registry, name, client.get("configuration"));
		}
	}

	------------ registerClientConfiguration ------------

	// 注册类型为 RibbonClientSpecification
	private void registerClientConfiguration(BeanDefinitionRegistry registry, Object name,
			Object configuration) {
		BeanDefinitionBuilder builder = BeanDefinitionBuilder
				.genericBeanDefinition(RibbonClientSpecification.class);
		builder.addConstructorArgValue(name);
		builder.addConstructorArgValue(configuration);
		registry.registerBeanDefinition(name + ".RibbonClientSpecification",
				builder.getBeanDefinition());
	}

RibbonAutoConfiguration

该类由 自动装配 加载,对应于 OpenFeignFeignContext,所有 RibbonContext上下文SpringClientFactory 创建和管理


	// 扫描的所有 RibbonClientSpecification
	@Autowired(required = false)
	private List<RibbonClientSpecification> configurations = new ArrayList<>();
	
	/**
	 * 将所有的 RibbonClientSpecification 交给 SpringClientFactory
	 * 		由 SpringClientFactory 创建和管理对应的 RibbonClient 上下文
	 * @return
	 */
	@Bean
	@ConditionalOnMissingBean
	public SpringClientFactory springClientFactory() {
		SpringClientFactory factory = new SpringClientFactory();
		factory.setConfigurations(this.configurations);
		return factory;
	}

这跟 FeignContext 的原理一模一样,因此不再过多解读,RibbonClient 对应的 上下文 创建与管理由 SpringClientFactory 实现

同时,RibbonAutoConfiguration 还创建了 LoadBalancerClient 的实例,为 RibbonLoadBalancerClient

	@Bean
	@ConditionalOnMissingBean(LoadBalancerClient.class)
	public LoadBalancerClient loadBalancerClient() {
		return new RibbonLoadBalancerClient(springClientFactory());
	}

LoadBalancerClient

LoadBalancerClientRibbon 的和核心接口,可以在 RestTempldate 发送网络请求时替代其进行网络调用,实现 负载均衡

LoadBalancerClient 继承了 ServiceInstanceChooser

这两个接口的定义都在 spring-cloud-commons 依赖中,属于通用接口

ServiceInstanceChooser

public interface ServiceInstanceChooser {

	// 从 LoadBalancer 获取一个服务实例
	ServiceInstance choose(String serviceId);

}

LoadBalancerClient

public interface LoadBalancerClient extends ServiceInstanceChooser {

	// 由获取的 服务实例 发送请求
	<T> T execute(String serviceId, LoadBalancerRequest<T> request) throws IOException;

	// 由获取的 服务实例 发送请求
	<T> T execute(String serviceId, ServiceInstance serviceInstance,
			LoadBalancerRequest<T> request) throws IOException;

	// 服务名 到 ip:port 的转换
	URI reconstructURI(ServiceInstance instance, URI original);

}

定义了 服务实例选择、请求执行 相关方法

RibbonLoadBalancerClient

RibbonLoadBalancerClientLoadBalancerClient 的实现


	-------------------- choose --------------------

	// 服务实例获取
	@Override
	public ServiceInstance choose(String serviceId) {
		return choose(serviceId, null);
	}

	public ServiceInstance choose(String serviceId, Object hint) {
		Server server = getServer(getLoadBalancer(serviceId), hint);
		if (server == null) {
			return null;
		}
		return new RibbonServer(serviceId, server, isSecure(server, serviceId),
				serverIntrospector(serviceId).getMetadata(server));
	}
	
	-------------------- execute --------------------

	public <T> T execute(String serviceId, LoadBalancerRequest<T> request, Object hint)
			throws IOException {
		// 从 上下文 中获取 ILoadBalancer,默认是 ZoneAwareLoadBalancer
		ILoadBalancer loadBalancer = getLoadBalancer(serviceId);
		
		// 获取服务实例 -> ILoadBalancer#chooseServer
		Server server = getServer(loadBalancer, hint);
		if (server == null) {
			throw new IllegalStateException("No instances available for " + serviceId);
		}
		
		// 封装成 RibbonServer
		RibbonServer ribbonServer = new RibbonServer(serviceId, server,
				isSecure(server, serviceId),
				serverIntrospector(serviceId).getMetadata(server));

		// 发送请求
		return execute(serviceId, ribbonServer, request);
	}

	-------------------- getServer --------------------
	
	protected Server getServer(ILoadBalancer loadBalancer, Object hint) {
		if (loadBalancer == null) {
			return null;
		}
		return loadBalancer.chooseServer(hint != null ? hint : "default");
	}
  • execute 方法:获取对应的 服务实例,发送请求
  • 服务实例的获取委托给 ILoadBalancer#chooseServer
  • ILoadBalancer 实例从 上下文 获取
  • choose 方法同样委托给 ILoadBalancer#chooseServer

题外话

可以大致如此梳理 Spring Cloud 的结构:

  • spring.cloud.commons 依赖抽象顶层接口,提供规范,比如 LoadBalancerClient
  • 具体的组件,如 spring.cloud.netflix.ribbon 提供对应的实现,比如 RibbonLoadBalancerClient,该部分主要是实现 Spring Cloud 的定制,可以理解为一层装饰,供 Spring Cloud 用户调用
  • 底层的实现,由对应的依赖提供,比如 com.netflix.ribbon

总结

本章节主要介绍了:

  • RibbonClientConfigurationRegistrar,注册对应 RibbonClient 的组件到容器中,由 SpringClientFactory 创建管理对应的 上下文
  • LoadBalancerClient负载均衡 顶层接口,底层委托给 ILoadBalancer 实现

下一章节,会具体介绍 ILoadBalancer 接口及其部分实现类

下一篇:【源码】Spring Cloud —— Ribbon 2 ILoadBalancer

参考

《Spring Cloud 微服务架构进阶》 —— 朱荣鑫 张天 黄迪璇

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值