【一起学源码-微服务】Ribbon 源码一:Ribbon概念理解及Demo调试
前言
前情回顾
前面文章已经梳理清楚了Eureka相关的概念及源码,接下来开始研究下Ribbon的实现原理。
我们都知道Ribbon在spring cloud中担当负载均衡的角色, 当两个Eureka Client互相调用的时候,Ribbon能够做到调用时的负载,保证多节点的客户端均匀接收请求。(这个有点类似于前端调用后端时Nginx做的负载均衡)
本讲目录
本讲主通过一个简单的demo来了解ribbon内部实现,这里主要是对ribbon有个宏观的认识,后续篇章会一步步通过debug的方式对ribbon的细节做一个全面的讲解。
目录如下:
- 一个demo来看看ribbon是做什么的
- @LoadBalanced初探
- LoadBalancerAutoConfiguration初探
- RibbonLoadBalancerClient初探
说明
原创不易,如若转载 请标明来源!
博客地址:一枝花算不算浪漫
微信公众号:壹枝花算不算浪漫 (文章底部有公众号二维码)
Ribbon正文
一个demo来看看ribbon是做什么的
首先看下我们这里的demo,目录结构如下:

这里有3个模块,eurekaServer作为注册中心,serviceA和serviceB分别作为EurekaClient。
代码地址上传到了自己的git:
https://github.com/barrywangmeng/spring-cloud-learn
ribbon相关的类结构信息
启动了eureka client如下:
服务A 2个: 一个端口号为8087,另一个为8088
服务B 1个

查看注册中心Dashboard

服务B调用服务A中的接口

查看负载均衡情况
第一次调用服务B的greeting方法:

第二次调用服务A的greeting方法:

这里可以看到服务A调用的时候加了一个注解: @LoadBalanced
服务B第一次调用到了服务A的8088那个节点
服务B第二次调用到了服务A的8087那个节点
这里就可以证明使用@LoadBalanced 自动对我们的http请求加了负载均衡,接下来我们就用@LoadBalanced来一步步往下看。
@LoadBalanced初探
接下来看下@LoadBalanced的源码:
/** * Annotation to mark a RestTemplate bean to be configured to use
a LoadBalancerClient * @author Spencer Gibb */@Target({ ElementType.FIELD, ElementType.PARAMETER,
ElementType.METHOD })@Retention(RetentionPolicy.RUNTIME)@Documented@Inherited@Qualifierpublic @interface LoadBalanced {}
这里主要看注释,这里意思是使用这个注解后可以将普通的RestTemplate 使用 LoadBalanceClient 这个类去处理。
接着我们看下LoadBalanced相关的配置。
LoadBalancerAutoConfiguration初探
我们知道,springboot + springcloud 对应的组件都会有相应的XXXAutoConfigure配置类,同理,我们在LoadBalanced同级包下可以找到对应的AutoConfigure类:LoadBalancerAutoConfiguration, 先看下类的定义:
@Configuration
@ConditionalOnClass(RestTemplate.class)
@ConditionalOnBean(LoadBalancerClient.class)
@EnableConfigurationProperties(LoadBalancerRetryProperties.class)
public class LoadBalancerAutoConfiguration {
}
看到这里有个 @ConditionalOnClass(RestTemplate.class),这个含义是 只有存在RestTemplate 这个类的时该配置才会生效。
接着看LoadBalancerAutoConfiguration中的一些方法:
public class LoadBalancerAutoConfiguration {
@LoadBalanced
@Autowired(required = false)
private List<RestTemplate> restTemplates = Collections.emptyList();
@Bean
public SmartInitializingSingleton loadBalancedRestTemplateInitializer(
final List<RestTemplateCustomizer> customizers) {
return new SmartInitializingSingleton() {
@Override
public void afterSingletonsInstantiated() {
for (RestTemplate restTemplate : LoadBalancerAutoConfiguration.this.restTemplates) {
for (RestTemplateCustomizer customizer : customizers) {
customizer.customize(restTemplate);
}
}
}
};
}
}
我们可以看下loadBalancedRestTemplateInitializer 方法,这个里面会遍历restTemplates然后调用customize() 方法进行特殊处理。
public class LoadBalancerAutoConfiguration {
@LoadBalanced
@Autowired(required = false)
private List<RestTemplate> restTemplates = Collections.emptyList();
@Configuration
@ConditionalOnMissingClass("org.springframework.retry.support.RetryTemplate")
static class LoadBalancerInterceptorConfig {
@Bean
public LoadBalancerInterceptor ribbonInterceptor(
LoadBalancerClient loadBalancerClient,
LoadBalancerRequestFactory requestFactory) {
return new LoadBalancerInterceptor(loadBalancerClient, requestFactory);
}
@Bean
@ConditionalOnMissingBean
public RestTemplateCustomizer restTemplateCustomizer(
final LoadBalancerInterceptor loadBalancerInterceptor) {
return new RestTemplateCustomizer() {
@Override
public void customize(RestTemplate restTemplate) {
List<ClientHttpRequestInterceptor> list = new ArrayList<>(
restTemplate.getInterceptors());
list.add(loadBalancerInterceptor);
restTemplate.setInterceptors(list);
}
};
}
}
}
这里面是为每一个restTemplate 添加一个loadBalancerInterceptor 拦截器,紧接着看一下LoadBalancerInterceptor.java
public class LoadBalancerInterceptor implements ClientHttpRequestInterceptor {
private LoadBalancerClient loadBalancer;
private LoadBalancerRequestFactory requestFactory;
@Override
public ClientHttpResponse intercept(final HttpRequest request, final byte[] body,
final ClientHttpRequestExecution execution) throws IOException {
final URI originalUri = request.getURI();
String serviceName = originalUri.getHost();
Assert.state(serviceName != null, "Request URI does not contain a valid hostname: " + originalUri);
return this.loadBalancer.execute(serviceName, requestFactory.createRequest(request, body, execution));
}
}
这里面就很简单了,将serviceName(这里就是对应我们demo中的:ServiceA)和request、body、excution等组成的新的request传递给LoadBalancerClient,然后调用其中的execute,这个方法的实现继续往下看RibbonLoadBalancerClient
RibbonLoadBalancerClient初探
接下来再看一下 LoadBalanceClient :
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;
URI reconstructURI(ServiceInstance instance, URI original);
}
这个接口只有一个实现类:RibbonLoadBalancerClient, 那么我们继续看实现类中的execute方法:
@Override
public <T> T execute(String serviceId, LoadBalancerRequest<T> request) throws IOException {
ILoadBalancer loadBalancer = getLoadBalancer(serviceId);
Server server = getServer(loadBalancer);
if (server == null) {
throw new IllegalStateException("No instances available for " + serviceId);
}
RibbonServer ribbonServer = new RibbonServer(serviceId, server, isSecure(server,
serviceId), serverIntrospector(serviceId).getMetadata(server));
return execute(serviceId, ribbonServer, request);
}
接着就可以在这个方法上愉快的debug了,我们先看看ILoadBalancer 是干嘛的:

我们通过debug可以看到 获取的ILoadBalancer 已经获取到服务A所有的节点信息了,这一章就先不延伸下去了,后面会详细来说ILoadBalancer处理的细节。
总结
这一篇主要讲解了一个RestTemplate 加上@LoadBalanced 注解后是如何获取到请求服务的多个节点信息的,通过debug 我们可以很清晰的看到请求流程,最后画一个图来总结一下:

申明
本文章首发自本人博客:https://www.cnblogs.com/wang-meng 和公众号:壹枝花算不算浪漫,如若转载请标明来源!
感兴趣的小伙伴可关注个人公众号:壹枝花算不算浪漫

【一起学源码-微服务】Ribbon 源码一:Ribbon概念理解及Demo调试的更多相关文章
- 【一起学源码-微服务】Ribbon源码五:Ribbon源码解读汇总篇~
前言 想说的话 [一起学源码-微服务-Ribbon]专栏到这里就已经全部结束了,共更新四篇文章. Ribbon比较小巧,这里是直接 读的spring cloud 内嵌封装的版本,里面的各种config ...
- 【一起学源码-微服务】Eureka+Ribbon+Feign阶段性总结
前言 想说的话 这里已经梳理完Eureka.Ribbon.Feign三大组件的基本原理了,今天做一个总结,里面会有一个比较详细的调用关系流程图. 说明 原创不易,如若转载 请标明来源! 博客地址:一枝 ...
- 【一起学源码-微服务】Nexflix Eureka 源码十:服务下线及实例摘除,一个client下线到底多久才会被其他实例感知?
前言 前情回顾 上一讲我们讲了 client端向server端发送心跳检查,也是默认每30钟发送一次,server端接收后会更新注册表的一个时间戳属性,然后一次心跳(续约)也就完成了. 本讲目录 这一 ...
- 【一起学源码-微服务】Nexflix Eureka 源码十三:Eureka源码解读完结撒花篇~!
前言 想说的话 [一起学源码-微服务-Netflix Eureka]专栏到这里就已经全部结束了. 实话实说,从最开始Eureka Server和Eureka Client初始化的流程还是一脸闷逼,到现 ...
- springcloud微服务实战:Eureka+Zuul+Feign/Ribbon+Hystrix Turbine+SpringConfig+sleuth+zipkin
相信现在已经有很多小伙伴已经或者准备使用springcloud微服务了,接下来为大家搭建一个微服务框架,后期可以自己进行扩展.会提供一个小案例: 服务提供者和服务消费者 ,消费者会调用提供者的服务,新 ...
- 【一起学源码-微服务】Feign 源码一:源码初探,通过Demo Debug Feign源码
前言 前情回顾 上一讲深入的讲解了Ribbon的初始化过程及Ribbon与Eureka的整合代码,与Eureka整合的类就是DiscoveryEnableNIWSServerList,同时在Dynam ...
- 【一起学源码-微服务】Nexflix Eureka 源码二:EurekaServer启动之配置文件加载以及面向接口的配置项读取
前言 上篇文章已经介绍了 为何要读netflix eureka源码了,这里就不再概述,下面开始正式源码解读的内容. 如若转载 请标明来源:一枝花算不算浪漫 代码总览 还记得上文中,我们通过web.xm ...
- 【一起学源码-微服务】Nexflix Eureka 源码八:EurekaClient注册表抓取 精妙设计分析!
前言 前情回顾 上一讲 我们通过单元测试 来梳理了EurekaClient是如何注册到server端,以及server端接收到请求是如何处理的,这里最重要的关注点是注册表的一个数据结构:Concurr ...
- 【一起学源码-微服务】Feign 源码二:Feign动态代理构造过程
前言 前情回顾 上一讲主要看了@EnableFeignClients中的registerBeanDefinitions()方法,这里面主要是 将EnableFeignClients注解对应的配置属性注 ...
随机推荐
- re模块下的常用方法
一 : re模块的查找 findall 优先级查找 返回列表 找所有的匹配项(从大段的内容中找匹配到的项目) import re str = "qwer asdf zxcv qwer ...
- oracle函数 NLS_LOWER(x[,y])
[功能]返回字符串并将字符串的变为小写; [参数]x字符型表达式 [参数]Nls_param可选,指定排序的方式(nls_sort=) . SCHINESE_RADICAL_M(部首.笔画) SCHI ...
- es6新增语法之`${}`
这是es6中新增的字符串方法 可以配合反单引号完成拼接字符串的功能 1.反单引号怎么打出来?将输入法调整为英文输入法,单击键盘上数字键1左边的按键. 2.用法step1: 定义需要拼接进去的字符串变量 ...
- pytorch 动态调整学习率 重点
深度炼丹如同炖排骨一般,需要先大火全局加热,紧接着中火炖出营养,最后转小火收汁.本文给出炼丹中的 “火候控制器”-- 学习率的几种调节方法,框架基于 pytorch 1. 自定义根据 epoch 改变 ...
- H3C 电路交换连接模型
- ccf-201403-3有趣的命令行
傻逼题,要是考试只能得0分.. 提供几组傻逼数据,这要是在真实的生活中一定是错的... 还是要好好读题吧,全凭自己的感觉就得0分 albw:x 4 ls -a docu Case 1: -a ls - ...
- poj 3384 Feng Shui (Half Plane Intersection)
3384 -- Feng Shui 构造半平面交,然后求凸包上最远点对. 这题的题意是给出一个凸多边形区域,要求在其中放置两个半径为r的圆(不能超出凸多边形区域),要求求出两个圆心,使得多边形中没有被 ...
- 全面解读Python Web开发框架Django,利用Django构建web应用及其部署
全面解读Python Web开发框架Django Django是一个开源的Web应用框架,由Python写成.采用MVC的软件设计模式,主要目标是使得开发复杂的.数据库驱动的网站变得简单.Django ...
- 大众点评实时监控系统CAT的那些坑
首先,感谢大众点评开源监控系统CAT.CAT是一款非常使用的功能建全的监控系统.作为一个知名的开源软件,真的是太差了. 想把CAT用起来,没有多年的Java经验是不行的.先吐槽一下,再写一篇如何用的文 ...
- artDialog4.0.5
artDialog4.0.5 2011-08-22 11:54:36 haiwei_sun 阅读数 4109 收藏 更多 分类专栏: jquery 下载 Google Code 项目主页 最新版 ...