@LoadBalanced注解用来给RestTemplate做标记,以使用负载均衡的客户端来配置。

通过搜索LoadBalancerClient可以发现,LoadBalancerClient是SpringCloud定义的一个接口

public interface LoadBalancerClient {
Serviceinstance choose(String serviceId);
<T> T execute(String serviceid, LoadBalancerRequest<T> request) throws
IOException;
URI reconstructURI(Serviceinstance instance, URI original);

}

通过该接口,了解客户端负载均衡器因该具备几种能力。

1.choose(String serviceId):根据传入的服务名serviceId,从负载均衡器中挑选一个对应的服务实例。

2.<T> T execute(String serviceid, LoadBalancerRequest<T> request):使用从负载均衡器中挑选服务实例来执行请求内容。

3.URI reconstructURI(Serviceinstance instance, URI original);:为系统构建一个合适的host:port形式的URI。在分布式系统中,我们使用逻辑上的服务名作为host来构建URI进行请求 。

LoadBalancerAutoConfiguration 类为实现客户端负载均衡的自动化配置类。通过查看配置类的源码。可以知道Ribbon实现的负载均衡自动化配置需要满足下面两个条件。

1.RestTemplate类必须存在于当前工程的环境中。

2.在Spring的Bean工程中必须有LoadBalancerClient的实现的Bean。

在改自动化配置类中,主要做了下面三个事:

1.创建了一个LoadBalancerInterceptor的Bean,用于实现客户端发起请求进行拦截,以实现客户端的负载均衡。

2.创建一个RestTemplateCustomizer的Bean,用于给RestTemplate增加LoadBalancerInterceptor拦截器。

3.维护了一个被@LoadBalanced注释修饰的RestTemplate对象列表。并在这里进行初始化,通过调用RestTemplateCustomizer的实例来给需要客户端负载均衡的RestTemplate增加LoadBalancerInterceptor拦截器。

通过源码分析,拦截器注入了LoadBalancerClient的实现,当一个被@LoadBalanced注解修饰的RestTemplate对象想外发起HTTP请求时,会被LoadBalancerInterceptor类的intercept函数所拦截。由于我们在使用RestTemplate时采用了服务名作为host,所以直接从HttpRequest的URI对象中通过getHost()就可以拿到服务名。然后调用execute函数去根据服务名来选择实例并发起实际的请求。

以上的LoadBalancerClient还只是一个抽象的负载均衡器接口,所以我们还需要找到他的具体实现类来进一步进行分析。他的具体实现类是RibbonLoadBalancerClient。

在RibbonLoadBalancerClient的execute函数实现中,第一步就是通过getServer根据传入的服务名serviceId去获得具体的服务实例。

SpringCloud默认财通了ZoneAwareLoadBalancer来实现负载均衡器。

通过ZoneAwareLoadBalancer的chooseServer函数获取了负载均衡策略分配到的服务实例对象Server之后,还将起对象包装成RibbonServer对象(该对象处理存储了服务实例的对象之外,还增加了服务名serviceId,是否需要使用HTTPS等其他信息),然后使用该对象在回调LoadBalancerInterceptor请求拦截器中LoadBalancerRequest的apply函数,向一个世纪的具体服务实例发起请求,从而实现一开始以服务名为host的URI请求到host:post形式的实际访问地址的转换。

在apply函数中传入的ServiceInstance接口对象是对服务实例的抽象定义,在改接口暴露了服务治理系统中每个服务实例需要提供的一些基本信息。比如serviceId,host,post等,具体定义如下。

public interface ServiceInstance {
String getServiceId(); String getHost(); int getPort(); boolean isSecure(); URI getUri(); Map<String, String> getMetadata();
}

  上面提到的具体包装Server服务实例的RibbonServer对象就是ServiceInstance接口的实现,可以看到他除了包装Server对象之外,还存储了服务名,是否使用HTTPS标识以及一个Map类型的元数据集合。

从apply的实现中,可以看到他具体执行的时候,还传入了ServiceRequestWrapper对象,该对象继承了HttpRequestWrapper并重写了getURI函数,重写后的getURI通过调用LoadBalancerClient接口的reconstructURI函数来重新构建一个URI来进行访问。

读书笔记-Ribbon源码分析的更多相关文章

  1. Nginx学习笔记4 源码分析

    Nginx学习笔记(四) 源码分析 源码分析 在茫茫的源码中,看到了几个好像挺熟悉的名字(socket/UDP/shmem).那就来看看这个文件吧!从简单的开始~~~ src/os/unix/Ngx_ ...

  2. Ribbon源码分析(二)-- 服务列表的获取和负载均衡算法分析

    上一篇博客(https://www.cnblogs.com/yangxiaohui227/p/12614343.html)分享了ribbon如何实现对http://product/info/这个链接重 ...

  3. Ribbon源码分析(一)-- RestTemplate 以及自定义负载均衡算法

    如果只是想看ribbon的自定义负载均衡配置,请查看: https://www.cnblogs.com/yangxiaohui227/p/13186004.html 注意: 1.RestTemplat ...

  4. Spring Cloud Ribbon 源码分析---负载均衡算法

    上一篇分析了Ribbon如何发送出去一个自带负载均衡效果的HTTP请求,本节就重点分析各个算法都是如何实现. 负载均衡整体是从IRule进去的: public interface IRule{ /* ...

  5. ribbon源码分析

    对于ribbon的使用我们只需要在RestTemplate的申明上面加上 @LoadBalanced 注解之后那么这个RestTemplate就具有了负载均衡的功能 ribbon是怎么实现这一功能的? ...

  6. 【黑客免杀攻防】读书笔记15 - 源码免杀、C++壳的编写

    1.源码免杀 1.1 定位产生特征的源码 定位文件特征 1.根据MyCCL的特征码定位工具,定位出有特征的地址 2.根据VS的反汇编窗口,输入有特征的地址得到特征地址与源码的关系 3.插入Messag ...

  7. Spring Cloud Ribbon源码分析---负载均衡实现

    上一篇结合 Eureka 和 Ribbon 搭建了服务注册中心,利用Ribbon实现了可配置负载均衡的服务调用.这一篇我们来分析Ribbon实现负载均衡的过程. 从 @LoadBalanced入手 还 ...

  8. ActiveMQ笔记:源码分析

    本文对ActiveMQ的启动过程,以及BrokerService,TransportConnector和NetworkConnector等几个重要的模块的代码做一个简要的分析. 启动过程 如果要快速地 ...

  9. odoo开发笔记--定时任务源码分析

    场景描述: 处理思路: 参考文章: 定时任务相关: https://www.jianshu.com/p/ad48239f84d6 https://blog.csdn.net/M0relia/artic ...

随机推荐

  1. 查询dubbo服务

    1.公司内网肯定会有服务治理平台,把自己提供的服务接口当关键字查询即可. 2.命令方式实现 查看本机Dubbo服务是否启动,telnet localhost [端口号],端口号是在注册dubbo服务的 ...

  2. Maven学习笔记—私服(包含maven的setting.xml配置)

    为什么要用远程仓库(私服) 如果没有私服,我们所需的所有构件都需要通过maven的中央仓库和第三方的maven仓库下载到本地,而一个团队中的所有人都重复的从maven仓库下载构件,这样就加大了中央仓库 ...

  3. JVM虚拟机—JVM内存

    JVM在运行时将数据划分为了5个区域来存储,这5个区域图示如下: 其中方法区和堆对是所有线程共享的内存区域:而java栈.本地方法栈和程序员计数器是运行时线程私有的内存区域. 首先我们熟悉一下一个 J ...

  4. Django web 框架

    目录 与Django的第一次见面 安装.文件解释与基本命令 Settings Models Views 路由系统 模板 Form表单 Cookie与Session CSRF防护

  5. Tensorflow 学习笔记(一)TensorFlow入门

    一.计算模型----计算图 1.1 计算图的概念:TensorFlow就是通过图的形式绘制出张量节点的计算过程,例如下图执行了一个a+b的操作. 1.2 计算图的使用 TensorFlow程序一般分为 ...

  6. Django——认证系统(Day72)

    阅读目录 COOKIE 与 SESSION 用户认证 COOKIE 与 SESSION 概念 cookie不属于http协议范围,由于http协议无法保持状态,但实际情况,我们却又需要“保持状态”,因 ...

  7. Codeforces Round #303 (Div. 2)

    A.Toy Cars 题意:给出n辆玩具车两两碰撞的结果,找出没有翻车过的玩具车. 思路:简单题.遍历即可. #include<iostream> #include<cstdio&g ...

  8. 微信小程序组件progress

    基础内容progress:官方文档 Demo Code: Page({ data:{ percent:0 }, onReady:function(){ this.percentAdd(); }, pe ...

  9. oracle中记录被另一个用户锁住的原因与解决办法

    oracle数据中删除数据时提示“记录被另一个用户锁住” 解决方法: 1.查看数据库锁,诊断锁的来源及类型: select object_id,session_id,locked_mode from ...

  10. LeetCode:累加数【306】

    LeetCode:累加数[306] 题目描述 累加数是一个字符串,组成它的数字可以形成累加序列. 一个有效的累加序列必须至少包含 3 个数.除了最开始的两个数以外,字符串中的其他数都等于它之前两个数相 ...