【源码】Spring Cloud —— Ribbon RibbonClientConfigurationRegistrar LoadBalancerClient 相关
前言
Ribbon 是管理 HTTP 和 TCP 服务客户端的 负载均衡器,作为 Spring Cloud 的 负载均衡 机制的实现,它可以与 OpenFeign 和 RestTemplate 无缝对接,让二者都具有 负载均衡 的能力
类似于 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 类
类比于 FeignClientsRegistrar,RibbonClientConfigurationRegistrar 也是一个 ImportBeanDefinitionRegistrar,为配置了注册了对应 RibbonClientSpecification 的 BeanDefinition,源码如下:
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
该类由 自动装配 加载,对应于 OpenFeign 的 FeignContext,所有 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
LoadBalancerClient 是 Ribbon 的和核心接口,可以在 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
RibbonLoadBalancerClient,LoadBalancerClient 的实现
-------------------- 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 微服务架构进阶》 —— 朱荣鑫 张天 黄迪璇