Spring Cloud - Openfeign 实现原理分析

OpenFeign简介

OpenFeign 是一个声明式 RESTful 网络请求客户端。OpenFeign 会根据带有注解的函数信息构建出网络请求的模板,在发送网络请求之前,OpenFeign 会将函数的参数值设置到这些请求模板中。虽然 OpenFeign 只能支持基于文本的网络请求,但是它可以极大简化网络请求的实现,方便编程人员快速构建自己的网络请求应用。

核心组件与概念

在阅读源码时,可以沿着两条线路进行,一是被@FeignClient注解修饰的接口类如何创建,也就是其 Bean 实例是如何被创建的;二是调用这些接口类的网络请求相关函数时,OpenFeign 是如何发送网络请求的。而 OpenFeign 相关的类也可以以此来进行分类,一部分是用来初始化相应的 Bean 实例的,一部分是用来在调用方法时发送网络请求。

动态注册BeanDefinition

1. FeignClientsRegistrar

@EnableFeignClients 有三个作用,一是引入FeignClientsRegistrar;二是指定扫描FeignClient的包信息,就是指定FeignClient接口类所在的包名;三是指定FeignClient接口类的自定义配置类。@EnableFeignClients注解的定义如下所示:

public @interface EnableFeignClients {// 下面三个函数都是为了指定需要扫描的包String[] value() default {};String[] basePackages() default {};Class<?>[] basePackageClasses() default {};// 指定自定义feign client的自定义配置,可以配置 Decoder、Encoder和Contract等组件// FeignClientsConfiguration 是默认的配置类Class<?>[] defaultConfiguration() default {};// 指定被@FeignClient修饰的类,如果不为空,那么路径自动检测机制会被关闭Class<?>[] clients() default {};
}
// org.springframework.cloud.openfeign.FeignClientsRegistrar#registerBeanDefinitions
@Override
public void registerBeanDefinitions(AnnotationMetadata metadata,BeanDefinitionRegistry registry) {// 从 EnableFeignClients 的属性值来构建 Feign 的自定义 Configuration 进行注册registerDefaultConfiguration(metadata, registry);// 扫描 package , 注册被 @FeignClient 修饰的接口类的Bean信息registerFeignClients(metadata, registry);
}
private void registerClientConfiguration(BeanDefinitionRegistry registry, Object name,Object configuration) {// 使用 BeanDefinitionBuilder 来生成 BeanDefinition, 并注册到 registry 上BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(FeignClientSpecification.class);builder.addConstructorArgValue(name);builder.addConstructorArgValue(configuration);registry.registerBeanDefinition(name + "." + FeignClientSpecification.class.getSimpleName(),builder.getBeanDefinition());
}

FeignClientSpecification 类实现了 NamedContextFactory.Specification 接口,它是 OpenFeign 组件实例化的重要一环,它持有自定义配置类提供的组件实例,供 OpenFeign 使用。SpringCloud 框架使用 NamedContextFactory 创建一系列的运行上下文,来让对应的 Specification 在这些上下文中创建实例对象。

// org.springframework.cloud.openfeign.FeignAutoConfiguration
@Autowired(required = false)
private List<FeignClientSpecification> configurations = new ArrayList<>();@Bean
public FeignContext feignContext() {// 创建 FeignContext 实例, 并将 FeignClientSpecification 注入FeignContext context = new FeignContext();context.setConfigurations(this.configurations);return context;
}
// org.springframework.cloud.openfeign.FeignContext#FeignContext
public FeignContext() {// 将默认的 FeignClientsConfiguration 作为参数传递给构造函数super(FeignClientsConfiguration.class, "feign", "feign.client.name");
}

NamedContextFactory 是 FeignContext 的父类, 其 createContext 方法会创建具有名称为 Spring 的AnnotationConfigApplicationContext 实例作为当前上下文的子上下文。这些 AnnotationConfigApplicationContext 实例可以管理 OpenFeign 组件的不同实例。

NamedContextFactory 的实现代码如下:

// org.springframework.cloud.context.named.NamedContextFactory#createContext
protected AnnotationConfigApplicationContext createContext(String name) {AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();// 获取该 name 所对应的 configuration ,如果有的话,就注册到子 context 中if (this.configurations.containsKey(name)) {for (Class<?> configuration : this.configurations.get(name).getConfiguration()) {context.register(configuration);}}// 注册 default 的 Configuration, 也就是 FeignClientsRegistrar 类的 registerDefaultConfiguration 方法中注册的Configurationfor (Map.Entry<String, C> entry : this.configurations.entrySet()) {if (entry.getKey().startsWith("default.")) {for (Class<?> configuration : entry.getValue().getConfiguration()) {context.register(configuration);}}}// 注册 PropertyPlaceholderAutoConfiguration 和 FeignClientsConfiguration 配置类context.register(PropertyPlaceholderAutoConfiguration.class, this.defaultConfigType);// 设置子 context 的 Environment 的 propertySource 属性源context.getEnvironment().getPropertySources().addFirst(new MapPropertySource(this.propertySourceName,Collections.<String, Object>singletonMap(this.propertyName, name)));// 所有 context 的 parent 都相同,这样的话,一些相同的Bean可以通过 parent context 来获取if (this.parent != null) {// Uses Environment from parent as well as beanscontext.setParent(this.parent);// jdk11 issue// https://github.com/spring-cloud/spring-cloud-netflix/issues/3101context.setClassLoader(this.parent.getClassLoader());}context.setDisplayName(generateDisplayName(name));context.refresh();return context;
}

2. 扫描类信息

FeignClientsRegistrar 做的第二件事情是扫描指定包下的类文件,注册 @FeignClient 注解修饰的接口类信息。

// org.springframework.cloud.openfeign.FeignClientsRegistrar#registerFeignClients
public void registerFeignClients(AnnotationMetadata metadata,BeanDefinitionRegistry registry) {// 自定义扫描类ClassPathScanningCandidateComponentProvider scanner = getScanner();scanner.setResourceLoader(this.resourceLoader);Set<String> basePackages;// 获取 EnableFeignClients 配置信息Map<String, Object> attrs = metadata.getAnnotationAttributes(EnableFeignClients.class.getName());// 依照 Annotation 来进行 TypeFilter ,只会扫描出被 FeignClient 修饰的类AnnotationTypeFilter annotationTypeFilter = n

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

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

相关文章

Kali开启远程服务

一&#xff0c;先切换root账户 二、kali开启远程服务 1&#xff0c;修改远程登录的配置文件 vim /etc/ssh/sshd_config &#xff08;用文本编辑器打开此文件) 在文件的普通模式下&#xff0c;使用/PermitRootLogin&#xff0c;回车&#xff0c;查找到该行&#xff0c;i&#…

【Java程序设计】【C00387】基于(JavaWeb)Springboot的校园食堂订餐系统(有论文)

基于&#xff08;JavaWeb&#xff09;Springboot的校园食堂订餐系统&#xff08;有论文&#xff09; 项目简介项目获取开发环境项目技术运行截图 博主介绍&#xff1a;java高级开发&#xff0c;从事互联网行业六年&#xff0c;已经做了六年的毕业设计程序开发&#xff0c;开发过…

OpenLayers6实战,OpenLayers绘制五角星,OpenLayers绘制特殊图形,地图上画五角星

专栏目录: OpenLayers实战进阶专栏目录 前言 本章讲解如何使用OpenLayers6在地图上绘制五角星这种特殊图形的功能。 本章上一章基础上修改而成:OpenLayers6实战,OpenLayers绘制特殊图形,OpenLayers绘制四角形(菱形),OpenLayers绘制菱形 二、依赖和使用 "ol&q…

【Linux】详细分析/dev/loop的基本知识 | 空间满了的解决方法

目录 前言1. 基本知识2. 内存满了2.1 清空2.2 扩增 3. 彩蛋 前言 服务器一直down机&#xff0c;翻找日志文件一直找不到缘由&#xff0c;最终发现是挂载的内存满了&#xff0c;那本身这个文件就什么用呢&#xff1f; 1. 基本知识 /dev/loop是一种特殊的设备文件&#xff0c;…

【问题处理】蓝鲸监控-数据断点解决

本文来自腾讯蓝鲸智云社区用户&#xff1a;fadewalk 在问答社区看到有小伙伴在落地蓝鲸的过程中出现监控平台的grafana面板数据断点问题&#xff0c;往往出现这种问题&#xff0c;都比较的头疼。 如果将CMDB&#xff08;配置管理数据库&#xff09;比作运维的基石&#xff0c;…

构建以太网交换网络——(生成树实验)

实验介绍 关于本实验 以太网交换网络中为了进行链路备份&#xff0c;提高网络可靠性&#xff0c;通常会使用冗余链路。但是使用冗余链路会在交换网络上产生环路&#xff0c;引发广播风暴以及MAC地址表不稳定等故障现象&#xff0c;从而导致用户通信质量较差&#xff0c;甚至…

用vscode调试cpp程序相关操作记录

需要在服务器上用vscode调试cpp程序&#xff0c;写此记录launch.json配置和相关步骤错误导致的问题 1.在需要运行程序的服务器上安装C/C Extension Pack&#xff08;之前只在本地装了&#xff09;&#xff0c;可以支持调试C/C应用程序(设置断点&#xff0c;单步执行&#xff0c…

【javaWeb 第三篇】Vue快速入门

VUE vue是一套前端框架&#xff0c;免除原生的js的DOM操作&#xff0c;简化书写 基于MVVM&#xff08;model-view-viewmodel&#xff09;思想&#xff0c;实现数据的双向绑定&#xff0c;将编程的关注放在数据上。 什么是框架&#xff1a; 框架相当于一个半成品&#xff0c;是一…

修复PSINS一个不常用的函数(getgnssvp)的小bug

PSINS工具箱的函数&#xff1a; vp getgnssvp(ephs, obss, tp, isfig)如上图&#xff0c;最后是绘图的标记“isfig”&#xff0c;但是实际这个标记没有用到&#xff0c;原函数内容&#xff1a; function vp getgnssvp(ephs, obss, tp, isfig) % see also findgpsobs. glob…

宜搭低代码高级认证实操题2 faas连接器加密解密

密钥维护页-保证有一条数据 敏感信息提交页 存档页&#xff0c;只是用来存数据的审批的时候不用这个表提交数据不然会出两条 授权查看页 FaaS连接器先下载好他的示例代码然后按照要求配置好参数直接拷贝进去就行 然后需要在云开发环境里面先new一个terminal然后跑一下./builde…

上位机图像处理和嵌入式模块部署(qmacvisual图像拼接)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 qmacvisual本身提供了图像拼接的功能。功能本身比较有意思的。大家如果拍过毕业照&#xff0c;特别是那种几百人、上千人的合照&#xff0c;应该就…

C++取经之路(其一)——namespace(命名空间),cout,cin(输入输出流),缺省参数。

前言&#xff1a; 最近开始学习C了&#xff0c;所以新开一个板块来记录&#xff0c;因为知道革命一路上荆棘丛生&#xff0c;所以取名为取经之路。 namespace(命名空间): 首先我们要知道::是域作用符号默认访问全局变量。 所谓命名空间&#xff0c;我称之为保护自己的财产&am…

yolov8 pose keypoint解读

yolov8进行关键点检测的代码如下&#xff1a; from ultralytics import YOLO# Load a model model YOLO(yolov8n.pt) # pretrained YOLOv8n model# Run batched inference on a list of images results model([im1.jpg, im2.jpg]) # return a list of Results objects# Pr…

PHP全自动采集在线高清壁纸网站源码

源码简介 集合360壁纸&#xff0c;百度壁纸&#xff0c;必应壁纸&#xff0c;简单方便。非常高清,支持全屏支持2K. 每天自动采集&#xff0c;自动更新&#xff0c;非常不错。 搭建环境 php5.6 Nginx 安装教程 上传源码压缩包到网站目录并解压即可 首页截图 源码下载 P…

day5-QT

widget.h #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include<QFontDialog> //字体对话框类 #include<QFont> //字体类 #include<QMessageBox> //消息对话框类 #include<QColorDialog> //颜色对话框类 #include<QColor> //颜…

【爬虫基础】第1讲 网络爬虫基本知识

什么是网络爬虫 网络爬虫&#xff08;Web crawler&#xff09;是一种自动化程序&#xff0c;用于在互联网上收集信息。它可以通过扫描和解析网页的超链接&#xff0c;自动访问网页并抓取所需的数据。网络爬虫常用于搜索引擎和数据采集工具中。 作用 通过有效的爬虫手段批量采…

【C语言】C语言基础习题详解(牛客网)二分查找逻辑

主页&#xff1a;醋溜马桶圈-CSDN博客 专栏&#xff1a;C语言_醋溜马桶圈的博客-CSDN博客 gitee&#xff1a;mnxcc (mnxcc) - Gitee.com 目录 1.三目运算符的使用 三目运算符&#xff0c;即a>b?a:b类型的&#xff0c;很多时候适当的使用三目运算符可以使得代码更简洁有序&…

vs2010打包QT程序

一、环境 win10 、 VS2010 、 qt5.7.1 将代码在release模式下运行 运行完后会在相应的文件夹下生成exe文件&#xff0c;也会将部分dll文件拷贝到release文件夹中 二、生成可执行文件 2.1 选择“文件”->“新建”->”项目“ 2.2 在打开的对框中选择”其他类型项目…

蓝桥杯学习笔记 单词分析

试题 G: 单词分析 时间限制: 1.0s 内存限制: 512.0MB 本题总分:20 分 [问题描述] 小蓝正在学习一门神奇的语言&#xff0c;这门语言中的单词都是由小写英文字母组成&#xff0c;有些单词很长&#xff0c;远远超过正常英文单词的长度。小蓝学了很长时间也记不住一些单词&#xf…

完全二叉树的层序遍历[天梯赛]

文章目录 题目描述思路 题目描述 输入样例 8 91 71 2 34 10 15 55 18 输出样例 18 34 55 71 2 10 15 91思路 完全二叉树最后一层可以不满&#xff0c;但上面的每一层的节点数都是满的 后序遍历的顺序为"左右根"&#xff0c;我们可以用数组模拟完全二叉树&#xff0c;…