来源:https://blog.csdn.net/zgz15515397650/article/details/125415419

OpenFeign 组件的前身是 Netflix Feign 项目,它最早是作为 Netflix OSS 项目的一部分,由 Netflix 公司开发。后来 Feign 项目被贡献给了开源组织,于是才有了我们今天使用的 Spring Cloud OpenFeign 组件。

OpenFeign 提供了一种声明式的远程调用接口,它可以大幅简化远程调用的编程体验。在了解 OpenFeign 的原理之前,先来体验一下 OpenFeign 的最终疗效。我用了一个Hello World 的小案例,带你看一下由 OpenFeign 发起的远程服务调用的代码风格是什么样的。

String response = helloWorldService.hello("Vincent Y.");

你可能会问,这不就是本地方法调用吗?没错!使用 OpenFeign 组件来实现远程调用非常简单,就像我们使用本地方法一样,只要一行代码就能实现 WebClient 组件好几行代码干的事情。而且这段代码不包含任何业务无关的信息,完美实现了调用逻辑和业务逻辑之间的职责分离。

那么,OpenFeign 组件在底层是如何实现远程调用的呢?接下来我就带你了解OpenFeign 组件背后的工作流程。

OpenFeign 使用了一种“动态代理”技术来封装远程服务调用的过程,我们在上面的例子中看到的 helloWorldService 其实是一个特殊的接口,它是由 OpenFeign 组件中的FeignClient 注解所声明的接口,接口中的代码如下所示。

@FeignClient(value = "hello-world-serv")
public interface HelloWorldService { @PostMapping("/sayHello") String hello(String guestName);
}

到这里你一定恍然大悟了,原来远程服务调用的信息被写在了 FeignClient 接口中。

在上面的代码里,你可以看到,服务的名称、接口类型、访问路径已经通过注解做了声明。

OpenFeign 通过解析这些注解标签生成一个“动态代理类”,这个代理类会将接口调用转化为一个远程服务调用的 Request,并发送给目标服务。

那么 OpenFeign 的动态代理是如何运作的呢?接下来,我就带你去深入了解这背后的流程。

我们创建了一个高质量的技术交流群,与优秀的人在一起,自己也会优秀起来,赶紧点击加群,享受一起成长的快乐。

OpenFeign 的动态代理

在项目初始化阶段,OpenFeign 会生成一个代理类,对所有通过该接口发起的远程调用进行动态代理。我画了一个流程图,帮你理解 OpenFeign 的动态代理流程:

上图中的步骤 1 到步骤 3 是在项目启动阶段加载完成的,只有第 4 步“调用远程服务”是发生在项目的运行阶段。

下面我来解释一下上图中的几个关键步骤。

首先,在项目启动阶段,OpenFeign 框架会发起一个主动的扫包流程,从指定的目录下扫描并加载所有被 @FeignClient 注解修饰的接口。

然后,OpenFeign 会针对每一个 FeignClient 接口生成一个动态代理对象,即图中的FeignProxyService,这个代理对象在继承关系上属于 FeignClient 注解所修饰的接口的实例。

接下来,这个动态代理对象会被添加到 Spring 上下文中,并注入到对应的服务里,也就是图中的 LocalService 服务。

最后,LocalService 会发起底层方法调用。实际上这个方法调用会被 OpenFeign 生成的代理对象接管,由代理对象发起一个远程服务调用,并将调用的结果返回给LocalService。

我猜你一定很好奇:OpenFeign 是如何通过动态代理技术创建代理对象的?我画了一张流程图帮你梳理这个过程,你可以参考一下。

我把 OpenFeign 组件加载过程的重要阶段画在了上图中。接下来我带你梳理一下OpenFeign 动态代理类的创建过程。

  1. 项目加载:在项目的启动阶段,EnableFeignClients 注解扮演了“启动开关”的角色,它使用 Spring 框架的 Import 注解导入了 FeignClientsRegistrar 类,开始了OpenFeign 组件的加载过程。

  2. 扫包:FeignClientsRegistrar 负责 FeignClient 接口的加载,它会在指定的包路径下扫描所有的 FeignClients 类,并构造 FeignClientFactoryBean 对象来解析FeignClient 接口。

  3. 解析 FeignClient 注解:FeignClientFactoryBean 有两个重要的功能,一个是解析FeignClient 接口中的请求路径和降级函数的配置信息;另一个是触发动态代理的构造过程。其中,动态代理构造是由更下一层的 ReflectiveFeign 完成的。

  4. 构建动态代理对象:ReflectiveFeign 包含了 OpenFeign 动态代理的核心逻辑,它主要负责创建出 FeignClient 接口的动态代理对象。ReflectiveFeign 在这个过程中有两个重要任务,一个是解析 FeignClient 接口上各个方法级别的注解,将其中的远程接口URL、接口类型(GET、POST 等)、各个请求参数等封装成元数据,并为每一个方法生成一个对应的 MethodHandler 类作为方法级别的代理;另一个重要任务是将这些MethodHandler 方法代理做进一步封装,通过 Java 标准的动态代理协议,构建一个实现了 InvocationHandler 接口的动态代理对象,并将这个动态代理对象绑定到FeignClient 接口上。这样一来,所有发生在 FeignClient 接口上的调用,最终都会由它背后的动态代理对象来承接。

MethodHandler 的构建过程涉及到了复杂的元数据解析,OpenFeign 组件将FeignClient 接口上的各种注解封装成元数据,并利用这些元数据把一个方法调用“翻译”成一个远程调用的 Request 请求。

那么上面说到的“元数据的解析”是如何完成的呢?

它依赖于 OpenFeign 组件中的Contract 协议解析功能。Contract 是 OpenFeign 组件中定义的顶层抽象接口,它有一系列的具体实现,其中和我们实战项目有关的是 SpringMvcContract 这个类,从这个类的名字中我们就能看出来,它是专门用来解析 Spring MVC 标签的。

SpringMvcContract 的继承结构是 SpringMvcContract->BaseContract->Contract。我这里拿一段 SpringMvcContract 的代码,帮助你深入理解它是如何将注解解析为元数据的。这段代码的主要功能是解析 FeignClient 方法级别上定义的 Spring MVC 注解。

// 解析FeignClient接口方法级别上的RequestMapping注解
protected void processAnnotationOnMethod(MethodMetadata data, Annotation methodAnnotation, Method method) {// 省略部分代码...// 如果方法上没有使用RequestMapping注解,则不进行解析// 其实GetMapping、PostMapping等注解都属于RequestMapping注解if (!RequestMapping.class.isInstance(methodAnnotation)&& !methodAnnotation.annotationType().isAnnotationPresent(RequestMapping.class)) {return;}// 获取RequestMapping注解实例RequestMapping methodMapping = findMergedAnnotation(method, RequestMapping.class);// 解析Http Method定义,即注解中的GET、POST、PUT、DELETE方法类型RequestMethod[] methods = methodMapping.method();// 如果没有定义methods属性则默认当前方法是个GET方法if (methods.length == 0) {methods = new RequestMethod[] { RequestMethod.GET };}checkOne(method, methods, "method");data.template().method(Request.HttpMethod.valueOf(methods[0].name()));// 解析Path属性,即方法上写明的请求路径checkAtMostOne(method, methodMapping.value(), "value");if (methodMapping.value().length > 0) {String pathValue = emptyToNull(methodMapping.value()[0]);if (pathValue != null) {pathValue = resolve(pathValue);// 如果path没有以斜杠开头,则补上/if (!pathValue.startsWith("/") && !data.template().path().endsWith("/")) {pathValue = "/" + pathValue;}data.template().uri(pathValue, true);if (data.template().decodeSlash() != decodeSlash) {data.template().decodeSlash(decodeSlash);}}}// 解析RequestMapping中定义的produces属性parseProduces(data, method, methodMapping);// 解析RequestMapping中定义的consumer属性parseConsumes(data, method, methodMapping);// 解析RequestMapping中定义的headers属性parseHeaders(data, method, methodMapping);data.indexToExpander(new LinkedHashMap<>());
}

通过上面的方法,我们可以看到,OpenFeign 对 RequestMappings 注解的各个属性都做了解析。

如果你在项目中使用的是 GetMapping、PostMapping 之类的注解,没有使用 RequestMapping,那么 OpenFeign 还能解析吗?当然可以。以 GetMapping 为例,它对 RequestMapping 注解做了一层封装。如果你查看下面关于 GetMapping 注解的代码,你会发现这个注解头上也挂了一个 RequestMapping 注解。因此 OpenFeign 可以正确识别 GetMapping 并完成加载。

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@RequestMapping(method = RequestMethod.GET)
public @interface GetMapping {
// ...省略部分代码
}

总结

今天你清楚了 OpenFeign 要解决的问题,我还带你了解了 OpenFeign 的工作流程,这里面的重点是动态代理机制。OpenFeing 通过 Java 动态代理生成了一个“代理类”,这个代理类将接口调用转化成为了一个远程服务调用。

------

我们创建了一个高质量的技术交流群,与优秀的人在一起,自己也会优秀起来,赶紧点击加群,享受一起成长的快乐。另外,如果你最近想跳槽的话,年前我花了2周时间收集了一波大厂面经,节后准备跳槽的可以点击这里领取!

推荐阅读

  • 电商系统的支付架构这样设计,稳的一批

  • ChatGPT 造富:大四学生放弃大厂去创业,半年后月收入45万

  • 终于有本书讲清了ChatGPT和AIGC的前世今生!

··································

你好,我是程序猿DD,10年开发老司机、阿里云MVP、腾讯云TVP、出过书创过业、国企4年互联网6年。从普通开发到架构师、再到合伙人。一路过来,给我最深的感受就是一定要不断学习并关注前沿。只要你能坚持下来,多思考、少抱怨、勤动手,就很容易实现弯道超车!所以,不要问我现在干什么是否来得及。如果你看好一个事情,一定是坚持了才能看到希望,而不是看到希望才去坚持。相信我,只要坚持下来,你一定比现在更好!如果你还没什么方向,可以先关注我,这里会经常分享一些前沿资讯,帮你积累弯道超车的资本。

OpenFeign 如何做到 隔空取物 ?相关推荐

  1. 5G智能互动机械臂机器人隔空取物天翼生态博览会AI人工智能手势捕捉高科技互动展览展会亮点活动跳跃互动tioyo

    2019天翼智能生态博览会以"hello 5G,赋能未来"为主题,主展区跳跃互动的5G智能互动机械臂<隔空取物>以高科技.新潮的互动方式吸引了大量来宾参与体验. 前往腾 ...

  2. 搭建Android上的服务器 “实现隔空取物”

    最近...因为无聊...对,傲娇的我因为无聊去看了鸿神的博客https://blog.csdn.net/lmj623565791/article/details/79081656 这里贴出来安利一下. ...

  3. 靠脑机接口“隔空探物”,大脑植入芯片可实现“心灵感应”

    来源:脑极体 1979年,在四川大足县的12岁农村少年唐雨突然具有了"耳朵识字"的神通.原本是当地的一件稀罕的谈资,结果后来引起了当地媒体的报道,后来又居然经过中国的权威科技期刊& ...

  4. 手机扫一扫就能“隔空移物”?AR炫酷新玩法,快来解锁新技能吧!

    关注上方"深度学习技术前沿",选择"星标公众号", 资源干货,第一时间送达! 转载自:量子位 魔法变现实,酷炫又实用. 还记得两年前,Zach King(男巫) ...

  5. 电脑断网也难逃黑客攻破!风扇在转,手机放桌上,数据就被隔空窃取了

    十三 发自 凹非寺 量子位 报道 | 公众号 QbitAI 网络安全.网络安全,有网络才不安全. 那么断网不就好了. 现在也不行了.万万没想到,用来散热的电脑风扇,也成了黑客窃取数据的对象. 让我们先 ...

  6. openCV手势识别之隔空移物

    如何用openCV隔空移苹果 WHY 前一阵子开始接触手势识别,觉得现在的库是真强大,13行代码就调出了手势识别,那手势识别出来后,可以做什么呢?今天,我又跟着印度小哥玩了一把隔空移物. WHAT 什 ...

  7. 利用Kinect实现用指尖隔空控制鼠标(源码放出)

    简介 此程序为利用Kinect实现用手指隔空控制鼠标,是我另一个项目的一部分,因为在另外那个项目中鼠标的click是通过一种特殊的方式实现的,因此这个程序只实现了用手控制鼠标的移动,并没有点击的功能. ...

  8. 互联网日报 | 1月31日 星期日 | 海航集团宣布破产重整;小米首发自研隔空充电技术;2021年春节档电影开启预售...

    今日看点 ✦ 海航集团:因不能清偿到期债务,债权人申请破产重整 ✦ 快手科技香港IPO定价为每股115港元,位于指导价区间高端 ✦ 小米首发隔空充电技术,可在数米半径内5瓦远距离充电 ✦ 各地出台就地 ...

  9. 基于Opencv实现的多彩隔空画图

    1.问题概述 人工智能带火了计算机视觉的人才需求,作为计算机视觉应用开发框架OpenCV也越来越受到欢迎,市场需求大增.因此,在学习Python的基础上,进行Opencv技术的学习是十分重要且有必要的 ...

最新文章

  1. oracle定时器怎么开启,Oracle的定时器使用示例
  2. 使用JNA解决自动化测试无法做密码输入操作的问题
  3. .NetCore如何使用ImageSharp进行图片的生成
  4. [蓝桥杯][历届试题]网络寻路-dfs,图的遍历
  5. atthesametime啥意思_eachother造句并翻译
  6. vsftpd的虚拟账户配置
  7. 马云:希望下辈子能做个好女人,男人离开女人“啥都不是”
  8. 《你不知道的JavaScript》-- 精读(一)
  9. 他面前有一个人,有一把刀
  10. 动态时间规整算法_如何使用动态时间规整算法进行语音识别
  11. Shiro - Shiro简介;Shiro与Spring Security区别;Spring Boot集成Shiro
  12. 危害极大的计算机病毒cih发作的日期是,计算机病毒防治(答案)
  13. Axure原型设计工具--产品经理必备
  14. 开源代码授权Licence说明
  15. Nielsen:网络广告信任度上升
  16. mysql 裸设备_什么叫做裸设备
  17. 手机Web前端调试页面之——Chrome DevTools(谷歌浏览器)的模拟手机调试
  18. 使用EXCEL绘制三维地图(超简单的五分钟绘制地图方法,妈妈再也不用担心我不会画地图啦~)
  19. Chrome浏览器中使用 iframe 嵌入网页导致视频不能全屏的问题解决方法
  20. 遍历Java中的列表

热门文章

  1. 1905协议详解(四)数据帧分析总览
  2. 【德诚视觉你值得拥有】
  3. Flash--散件与元件相互转换
  4. Blog--›Mac TNT 软件下载地址
  5. linux目录权限子目录权限,linux中更改所有子文件和子目录所有者权限
  6. 【python】将bytes转换为float* 每四字节转化为float
  7. 清华大学出版社c语言程序设计第五版,清华大学出版社-图书详情-《C程序设计教程(第5版)》...
  8. Excel 文件的生成与下载
  9. WPF学习第九集-深入浅出话命令
  10. Test time augmentation(TTA)