Feign 体系架构解析

正所谓麻雀虽小五脏俱全,HTTP 调用看着简单,实则下面隐藏的是一套非常复杂的流程。

从上古时代 jsp+servlet,到后面的 SpringMVC,在 HTTP 请求解析和封装上同样是煞费苦心。

在这里插入图片描述
我们在学习中经常会碰到这种 case,有些开源组件不显山来不露水,乍一看功能很简单,配置起来也不麻烦,让人感觉实现起来也不难。实际上我们所看到的只是冰山上的一角,在冰山下面隐藏的巨大基座才是这套技术的全貌。

就像 Feign 一样,往往以一个注解开场的项目,背后的故事都不简单。接下来,我们就潜入深海,看看 Feign 这座冰山的架构全景。

武装到牙齿 - Feign 体系架构

图片来自于电影《黑衣人》
大家有没有看过一部叫做《黑衣人》的电影?这部电影讲述了搞笑特工联手对抗外星生物,维护世界和平的故事。里面有一句经典台词叫做武装到牙齿,意思是几位特工身上任何部位都被武装到位,甚至牙齿也不放过。

Feign 就是这样一位被武装到牙齿的特工,Feign 的每个运作流程都包含了复杂的业务处理,NetflixFeign 更是关爱有加,甚至还给配备了两件重武器:RibbonHystrix。由于Feign 的调用链路比较长,所以我删减了很多支线剧情,只玩主线剧情,我们分为上下半场两张图给大家介绍 Feign 的架构全貌。

如果用一句话来介绍 Feign,那就是:声明一个代理接口,服务调用者通过调用这个代理接口的方式来调用远程服务。这样一来,调用远程方法就如同调用本地接口一样方便。

上半场 - 构建请求

左右护法:大伙现在看出 Feign 是个什么腕儿了吗?看那身旁站着 Ribbon Hystrix,左青龙右白虎,给 Feign 保驾护航。没错,Feign 自己兜里就揣着Ribbon Hystrix 两把重武器,引入Feign依赖的同时这两个组件也会被一同引入。

  • Ribbon:利用负载均衡策略选定目标机器。
  • Hystrix:根据熔断器的开启状态,决定是否发起此次调用
  1. 动态代理:Feign 是通过一个代理接口进行远程调用,这一步就是为了构造接口的动态代理对象,用来代理远程服务的真实调用,这样你就可以像调用本地方法一样发起 HTTP 请求,不需要像 Ribbon 或者 Eureka 那样在方法调用的地方提供服务名。在 Feign 中动态代理是通过Feign.build返回的构造器来装配相关参数,然后调用 ReflectFeignnewInstance 方法创建的。这里就应用到了Builder设计模式。
  2. Contract:协议,顾名思义,就像HTTP协议,RPC 协议一样,Feign 也有自己的一套协议的规范,只不过他解析的不是 HTTP 请求,而是上一步提到的动态代理类。通过解析动态代理接口+Builder 模式,Contract 协议会构造复杂的元数据对象 MethodMetadata,这里面包含了动态代理接口定义的所有特征。接下来,根据这些元数据生成一系列 MethodHandler 对象用来处理 RequestResponse 请求。Contract 具有高度可扩展性,可以经由对 Contract 的扩展,将 Feign 集成到其他开源组件之中。

番外篇 - 关于 Builder 模式

Builder 是设计模式中的一种,用来简化复杂组件的装配过程,假如用传统方式构建一个House 类,那应该是这样写:

House house = ne House();
house.setWindow("open");
house.setDoor("close");

Builder 模式是用链式构造的方式创建复杂对象,比如这种形式House.builder().window("open").door("close").build()这里教大家一个简单的实现方式,那就是 lombok 小工具的@Builder 注解,只要在 pom中添加 lombok 依赖,并且在 IDE 中添加 lombok 的插件,就可以用注解的方法,不用写一行代码就能实现 Builder 模式。

下半场 - 发起调用

  1. 拦截器 :拦截器是 Spring 处理网络请求的经典方案,Feign 这里也沿用了这个做法,通过一系列的拦截器对 Request 和 Response 对象进行装饰,比如通过 RequestInterceptorRequest 对象构造请求头。整装待发之后,就是正式发起调用的时候了。
  2. 发起请求:又到了左右护法的出场镜头了。这哼哈二将绝不放过开头和结尾两处重要镜头,正所谓从头到尾都参与了进来。重试:Feign 这里借助Ribbon 的配置重试器实现了重试操作,可以指定对当前服务节点发起重试,也可以让 Feign 换一个服务节点重试。
  3. 降级Feign 接口在声明时可以指定 Hystrix 的降级策略实现类,如果达到了 Hystrix 的超时判定,或得到了异常结果,将执行指定的降级逻辑。

Feign 之动态代理

动态代理 是面试场景里的高频问题,从 Spring 中 AOP 的实现方式,到让自己手写一个动“态代理实例,这个话题仿佛成了面试中很有仪式感的一个问题。面试官开口问到 请说出你对 ” aop ”的理解 ,感觉就像汪峰导师在问 你的梦想是什么 。

可是代理就代理好了,为什么要加个 “动态” 二字呢,难道还有静态代理一说?简单的说,所谓动态是相对于 “静态编译” 来说的。在 java 中,假如我们在编译期不知道这个对象是何方神圣,只能等待程序执行的时候,也就在是运行期才能知道,那么我们就称之为 “动态” 获取对象(比如通过类名+ 反射创建一个实例)。而所谓 “动态代理” ,就是指在运行期指定一个代理对象,以接管的方式执行后续的任务。就是这么简单。

Feign 的 动态代理 是个偷天换日的过程。我们把目标服务看做一个新娘子,当服务调用请求发出后,一伙迎亲车队浩浩荡荡地出发去迎亲。这时候,一伙打着 Feign 名号的抢亲小队出现了,他们利用 “动态代理” 的方式,截胡了迎亲车队,自个儿当起了新郎官去接新娘。我们这就来看看这伙抢亲小队是怎么工作的。

抢亲小队 - 截胡方法调用

问:截胡迎亲小队总共分几步?总共分四步:
在这里插入图片描述

我们来一起看下Feign 的源码。

  1. ·GetObject· :原配的迎亲小队出发了,一路喊着 “接对象咯”(getObject),成功吸引到了抢亲小队的注意力。
  • 这一步是 FeignClientFactoryBeangetObject 方法发起的,为了获取一个可以发起远程调用的实体方法,只是这时它还不知道,getObject ()方法获取到的其实是一个代理对象。
  • 我们知道 Feign 实际上是调用了@FeignClient 注解所修饰的接口,FeignClientFactoryBean 封装了这个接口中所包含的配置信息,比如Eureka服务名称,服务调用的路径,降级逻辑的处理类,等等。
  1. 创建代理对象:一伙抢亲小队听到风声,立马开始着手准备埋伏。在上一步的getObject 方法的最后做好了埋伏,开始了偷天换日的过程。
  • 上一步中 getObject 最后一行,经由 Targeter 类的转发,抢亲小队登场了。
  • 下面就是创建代理对象的时候了,Feign 的所有代理实例均通过ReflectiveFeign.newInstance 创建,他的底层是采用 Builder 模式,将@FeignClient 接口的特征,方法名,参数等等一系列信息提取出来,拼装成Java 反射机制中通用的 Method 类。
  • 偷天换日:这一步是整个动态代理机制中的核心操作。在newInstance·的创建过程中,Feign 通过实现 JDK 的 InvocationHandler接口(所有动态代理方案几乎都和它有关联),将自己的 Handler 和上一步组装的 Method 进行了关联,这样一来,所有对这个接口方法的调用,都将被 Feign 自定义的InvocationHandler 给接管。这种动态代理的方式,我们叫做 JDK 动态代理
  • 所有一切就绪,就等截胡方法调用了
  1. 拦截请求:这时迎亲车队经过了,因为我们在前一步已经做了埋伏,这个方法调用立马被我们自己人,也就是上一步中自定义的InvocationHandler 截胡了。
  • SynchronousMethodHandler 这时接管了 invoke 方法。构造 Request
    求,装模作样当起了新郎官。(在构造 Request 请求的同时还会涉及一系列的参数拼装和加密等步骤)
  1. 发起调用:最后一步,借助 LoadBalancerFeignClient 发起了真正的HTTP 请求。从这个类的名字大家可以看到,似乎和负载均衡有点关系?没错,这个就是 Feign 和 Ribbon组合而成的一个 Client 类,它会利用 Ribbon 实现超时重试等操作。前面讲到过,Feign 是武装到牙齿的组件,每一步的背后都有非常复杂的处理流程。

Spring 的动态代理

Spring 的 AOP 有两种动态代理方式,其中一种就是前面讲到的Feign采用的方式:JDK 动态代理。在 Spring 中通过 JdkDynamicAopProxy 实现。它有两个特点

  • 实现 InvocationHandler 接口,接管invoke方法实现自己的业务逻辑,所有调用都会被传递到 InvocationHandlerinvoke 方法,通过
    Proxy.newProxyInstance 获取动态代理对象
  • 被代理的对象必须实现了某个接口,不能代理无接口的类。Spring 还有一种动态代理的方式,那就是 CGLIB,它并不强制代理类实现某个接口。在实际使用中,CGLIB 在代理对象的性能方面比 JDKDynamic 要快很多,但是在创建代理对象上的时间花费也相当长。所以,如果你的类并没有实现接口,或者是单例模式的类不需要重复创建,建议使用 CGLIB 的方式。

本文已收录至我的个人网站:程序员波特,主要记录Java相关技术系列教程,共享电子书、Java学习路线、视频教程、简历模板和面试题等学习资源,让想要学习的你,不再迷茫。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/652793.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

阿里云一键部署搭建幻兽帕鲁联机服务器教程

幻兽帕鲁(Palworld)是一款多人在线游戏,为了获得更好的游戏体验,许多玩家会选择自行搭建游戏联机服务器,但是如何部署搭建幻兽帕鲁联机服务器成为一个难题,阿里云提供了一种高效且简便的一键部署方案&#…

qt初入门7:进度条,定时器,时间控件练习

参考课本demo,空闲时间练习一下进度条,定时器,日期相关控件和使用。 1:demo运行结果 2:进度条控件梳理 进度条显示控件实际上是QProgressBar, 显示的进度可以通过代码控制,也可以通过其他控件上获取到的值…

学习PyQt5

1、布局之后,无法移动对象到指定区域,无法改变对象大小。 原因:因为CtrlA选中了整个窗口,然后布局的时候就相当于整个窗口都按照这种布局,如选了水平布局,按钮一直在中间,无法拖到其它位置。 …

Unity之动画和角色控制

目录 📕 一、动画 1.创建最简单的动画 2.动画控制器 📕二、把动画和角色控制相结合 📕三、实现实例 3.1 鼠标控制角色视角旋转 3.2 拖尾效果 📕四、混合动画 最近学到动画了,顺便把之前创建的地形&#xff0…

go语言数组和切片

1. 数组Array Golang Array和以往认知的数组有很大不同。 1. 数组:是同一种数据类型的固定长度的序列。2. 数组定义:var a [len]int,比如:var a [5]int,数组长度必须是常量,且是类型的组成部分。一旦定义&…

Redis3-秒杀活动

秒杀 准备工作 我是参照下面这位大佬的i骄傲成下载的 csdn友情链接 Jmeter模拟多线程的压力测试工具 秒杀代码: package com.aaa.controller;import io.netty.util.internal.StringUtil; import org.apache.commons.lang.StringUtils; import org.springfram…

【大数据】详解 Flink 中的 WaterMark

详解 Flink 中的 WaterMark 1.基础概念1.1 流处理1.2 乱序1.3 窗口及其生命周期1.4 Keyed vs Non-Keyed1.5 Flink 中的时间 2.Watermark2.1 案例一2.2 案例二2.3 如何设置最大乱序时间2.4 延迟数据重定向 3.在 DDL 中的定义3.1 事件时间3.2 处理时间 1.基础概念 1.1 流处理 流…

深度推荐模型之DeepFM

一、FM 背景:主要解决大规模稀疏数据下的特征组合遇到的问题:1. 二阶特征参数数据呈指数增长 怎么做的:对每个特征引入大小为k的隐向量,两两特征的权重值通过计算对应特征的隐向量内积 而特征之间计算点积的复杂度原本为 实际应…

幻兽帕鲁的搭建和幻兽帕鲁需要什么配置的服务器

前言 大家好,今天教大家如何快速搭建幻兽帕鲁,并能满足8-32人游玩 第一步 购买服务器 1.CPU:4核(最低需要4核起,当然可以选择更高的)CPU的选择更看重单核性能,尽量选择主频2.5GHz以上的&#…

OpenTCS IDEA 全流程搭建和运行指南

OpenTCS IDEA 全流程搭建和运行指南 JDK安装下载JDK版本 openTCS源码下载IDEA 打开运行查看下载源码中gradle版本号下载gradle 二进制文件配置IDEA Gradle本地仓库IDEA打开openTCS项目运行顺序 JDK安装 下载JDK版本 JDK网址 注意: 请下载官方文档标准的java13JDK o…

4G模块Air724如何访问天气信息

1.这是获得json数据: 左边是标准官方api说明中的,右边是我用串口获取的: 2.首先找一个天气服务器,我的:YY天气,直接百度,注册,然后找api即可: 3.用接口工具测试接口是否…

AV Foundation 视频播放中的可视拖拽进度条

引言 在视频播放软件中,通过拖拽进度条来调整播放进度几乎已成为不可或缺的功能。这一功能使用户能够精确指定视频播放的时间点。近年来,视频播放器在原有的拖拽进度条基础上进行了更加人性化的性能提升,引入了可视化拖拽条。这一创新为用户…

Ps:根据 HSB 调色(以可选颜色命令为例)

在数字色彩中,RGB 和 HSV(又称 HSB)是两种常用的颜色表示方式(颜色模型)。 在 RGB 颜色模式下,Photoshop 的红(Red)、绿(Green)、蓝(Blue&#xf…

基于SpringBoot微信小程序的宠物美容预约系统设计与实现

博主介绍:✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、Java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和学生毕业项目实战,高校老师/讲师/同行交流合作✌ 主要内容:SpringBoot、Vue、SSM、HLM…

rabbitmq基础-java-3、Fanout交换机

1、简介 Fanout,英文翻译是扇出。 2、 特点 1) 可以有多个队列 2) 每个队列都要绑定到Exchange(交换机) 3) 生产者发送的消息,只能发送到交换机 4) 交换机把消息发送给绑定过的…

应用机器学习的建议

一、决定下一步做什么 在你得到你的学习参数以后,如果你要将你的假设函数放到一组新的房屋样本上进行测试,假如说你在预测房价时产生了巨大的误差,你想改进这个算法,接下来应该怎么办?实际上你可以考虑先采用下面的几种…

防御保护--第一次实验

目录 一,vlan的划分及在防火墙上创建单臂路由 二,创建安全区域 三,配置安全策略 四,配置认证策略 五,配置NAT策略 1.将内网中各个接口能够ping通自己的网关 2..生产区在工作时间内可以访问服务器区,仅…

AI大模型开发架构设计(6)——AIGC时代,如何求职、转型与选择?

文章目录 AIGC时代,如何求职、转型与选择?1 新职场,普通人最值钱的能力是什么?2 新职场成长的3点建议第1点:目标感第2点:执行力第3点:高效生产力 3 新职场会产生哪些新岗位机会?如何借势?4 新职场普通人…

数据结构-线性表

文章目录 数据结构—线性表1.线性表的定义和基本操作线性表的定义线性表的特点线性表的基本操作 2.线性表的顺序存储和链式存储表示顺序存储链式存储单链表循环链表双向链表 数据结构—线性表 1.线性表的定义和基本操作 线性表的定义 定义:线性表是具有相同数据类…

数据结构篇-03:堆实现优先级队列

本文着重在于讲解用 “堆实现优先级队列” 以及优先级队列的应用,在本文所举的例子中,可能使用优先级队列来解并不是最优解法,但是正如我所说的:本文着重在于讲解“堆实现优先级队列” 堆实现优先级队列 堆的主要应用有两个&…