【OpenFeign】【源码+图解】【二】注册OpenFeign接口的实例

news2025/2/23 6:06:59

【OpenFeign】【源码+图解】【一】HelloWorld及其工作原理

目录

  • 3. 注册OpenFeign接口的实例

3. 注册OpenFeign接口的实例

从HelloWorld中我们看到需要显示加入**@EnableFeignClients注解才能开启openFeign的功能,因此它就成为我们分析openFeign**的入口,先看下这个Annotation的属性

@Import(FeignClientsRegistrar.class) // 这个注册类是关键
public @interface EnableFeignClients {
    // 扫描的包,用于寻找open-feign客户端
	String[] value() default {};
    // 与value()一样
	String[] basePackages() default {};
    // 与value()的字符串不同,这里用的是Class类
	Class<?>[] basePackageClasses() default {};
    // 这里声明的配置会在所有的open-feign的clients生效
	Class<?>[] defaultConfiguration() default {};
    // @FeignClient声明的类,如果不为空的话前面的包扫描会失效
	Class<?>[] clients() default {};
}

先看下FeignClientsRegistrar的类图

在这里插入图片描述

从类图中可以看出FeignClientsRegistrar有以下作用

  1. 注册beans
  2. 获取配置Environment
  3. 获取资源加载器ResourceLoader

那么,接下来我们就开始分析FeignClientsRegistrar要注册哪些beans,入口是实现ImportBeanDefinitionRegistrar接口的registerBeanDefinitions方法

class FeignClientsRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware, EnvironmentAware {
    @Override
	public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
        // 1、注册默认的配置,即@EnableFeignClients中的defaultConfiguration,这个是所有FeignClients都有的
		registerDefaultConfiguration(metadata, registry);
        // 2、注册FeignClients
		registerFeignClients(metadata, registry);
	}
}

整体过程如下

在这里插入图片描述

中间涉及的源码过多,不做过多的具体分析,只探讨绿色的两部分,因为这两部分也是后续的开始

在开始之前我们先认识下**@FeignClient**

public @interface FeignClient {
	// client名字
	@AliasFor("name")
	String value() default "";
	// context名字
	String contextId() default "";
	@AliasFor("value")
	String name() default "";
	// 别名
	String[] qualifiers() default {};
	// 类似@RequestMapping声明的base url
	String url() default "";
	boolean decode404() default false;
	// client的配置,不同于@EnableFeignClients的defaultConfiguration,这个configuration只属于某个client
	Class<?>[] configuration() default {};
    // 降级处理的实例,需实现FeignClient
	Class<?> fallback() default void.class;
    // 降级处理实例的创建工厂,需实现FallbackFactory接口
	Class<?> fallbackFactory() default void.class;
	String path() default "";
	boolean primary() default true;

}

在使用中**@FeignClient**是用在接口上,而接口需要实例化才能使用,而绿色的两部分就是创建接口实例的过程,接下来分析是怎么利用其参数来创建实例的

class FeignClientsRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware, EnvironmentAware {
    private void registerFeignClient(BeanDefinitionRegistry registry, AnnotationMetadata annotationMetadata,
			Map<String, Object> attributes) {
		......
        // 本代码以HelloWorld中的ProductFeignClient为例探讨
		FeignClientFactoryBean factoryBean = new FeignClientFactoryBean();
		factoryBean.setBeanFactory(beanFactory);  // DefaultListableBeanFactory
		factoryBean.setName(name); // product
		factoryBean.setContextId(contextId); // product
		factoryBean.setType(clazz); // interface com.lanna.openfeign.ProductFeignClient
		factoryBean.setRefreshableClient(isClientRefreshEnabled()); // yml文件中的feign.client.refresh-enabled
		BeanDefinitionBuilder definition = BeanDefinitionBuilder.genericBeanDefinition(clazz, () -> {
			factoryBean.setUrl(getUrl(beanFactory, attributes)); // @FeignClient.url,默认""
			factoryBean.setPath(getPath(beanFactory, attributes)); // @FeignClient.path,默认""
            // @FeignClient.decode404,默认false。如果为true,当遇到404错误时不直接抛异常
			factoryBean.setDecode404(Boolean.parseBoolean(String.valueOf(attributes.get("decode404"))));
			Object fallback = attributes.get("fallback");
            // @FeignClient.fallback。fallback类必须实现@FeignClient的接口并且在spring的容器中
			if (fallback != null) {
				factoryBean.setFallback(fallback instanceof Class ? (Class<?>) fallback
						: ClassUtils.resolveClassName(fallback.toString(), null));
			}
            // @FeignClient.fallbackFactory。fallbackFactory: 
            // 1、必须实现FallbackFactory接口,2、必须能创建@FeignClient接口的实例,3、必须在spring的容器中
			Object fallbackFactory = attributes.get("fallbackFactory");
			if (fallbackFactory != null) {
				factoryBean.setFallbackFactory(fallbackFactory instanceof Class ? (Class<?>) fallbackFactory
						: ClassUtils.resolveClassName(fallbackFactory.toString(), null));
			}
            // 创建@FeignClient接口(即ProductFeignClient)的proxy实例
			return factoryBean.getObject();
		});
		definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
        // 设置延迟初始化。如果声明的FeignClient没有使用的话不会初始化
		definition.setLazyInit(true);
        // 验证参数
		validate(attributes);

		AbstractBeanDefinition beanDefinition = definition.getBeanDefinition();
        // factoryBeanObjectType: com.lanna.openfeign.ProductFeignClient
		beanDefinition.setAttribute(FactoryBean.OBJECT_TYPE_ATTRIBUTE, className);
        // feignClientsRegistrarFactoryBean: factoryBean
		beanDefinition.setAttribute("feignClientsRegistrarFactoryBean", factoryBean);

		// @FeignClient.primary,默认true
		beanDefinition.setPrimary(primary);

		// 别名qualifiers:@FeignClient.qualifiers
		BeanDefinitionHolder holder = new BeanDefinitionHolder(beanDefinition, className, qualifiers);
        // 注册com.lanna.openfeign.ProductFeignClient
		BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry);
        // 如果feign.client.refresh-enabled开启(默认false),注册名为contextId的OptionsFactoryBean
		registerOptionsBeanDefinition(registry, contextId);
	}
}

注册OpenFeign的beans实例过程就分析到此,代码中definition.setLazyInit(true)设置了延迟加载,通俗点理解就是如果代码中没有通过@Autowired注入bean的话是不会调用factoryBean.getObject()的。接下来我们就看看factoryBean.getObject()是如何创建FeignClient的client,即ProductFeignClient的实例。

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

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

相关文章

Chrony时间同步服务

目录 一、时间同步 1.概念 2.时间同步在运维工作中的作用 3.时间同步完成方法 &#xff08;1&#xff09;NTP时间服务&#xff08;centos 6 &#xff09; &#xff08;2&#xff09;Chrony时间服务 二、Chrony时间服务 1.Chrony介绍 2.Chrony的优点 三、Chrony安装 …

逻辑回归(Logistic Regression)原理及过程

目录 一&#xff1a;逻辑回归简介 二&#xff1a;逻辑回归原理 三&#xff1a;逻辑回归 损失函数 四&#xff1a;逻辑回归 梯度下降算法 五&#xff1a;逻辑回归 过程 一&#xff1a;逻辑回归简介 Logistic模型是1938年Verhulst-Pearl在修正非密度方程时提出来的&#xf…

算法刷题打卡第49天:排序数组---计数排序

排序数组 难度&#xff1a;中等 给你一个整数数组 nums&#xff0c;请你将该数组升序排列。 示例 1&#xff1a; 输入&#xff1a;nums [5,2,3,1] 输出&#xff1a;[1,2,3,5]示例 2&#xff1a; 输入&#xff1a;nums [5,1,1,2,0,0] 输出&#xff1a;[0,0,1,1,2,5]计数排…

我与世界杯的故事——达利奇:铜牌闪耀着金光

目录 克罗地亚球队的历史 奇迹出现 心得总结 克罗地亚球队的历史 克罗地亚球队拥有悠久的历史&#xff1a; 1998年首次亮相法国世界杯&#xff0c;克罗地亚就以季军的战绩惊艳众人。 2018年的俄罗斯世界杯&#xff0c;虽然格子军团在决赛中不敌强大的法国&#xff0c;遗憾地…

<Linux进程通信之共享内存>——《Linux》

目录 一、system V共享机制 1.共享内存示意图 2.共享内存数据结构 3.共享内存函数 3.1shmget函数 3.2 shmat函数 3.3 shmdt函数 3.4 shmctl函数 3.5 实例代码&#xff1a; 3.6 结果演示&#xff1a; 4. 创建共享内存 5. 基于共享内存与管道进行访问控制的共享内存读…

(P4)Python plt显示图像

Python plt显示图片 本地可以显示&#xff0c;服务器操作不太行。 plt.plot(x,y) plt.imshow(image) plt.show() # 显示图像&#xff08;曲线/图片都需要这一行&#xff09; plt.savefig(xx.png) # 保存图片 fig.savefig(xx.png) 功能相同 # 保存图片在本地执行失败&#xff…

Elasticsearch学习笔记

Elasticsearch学习笔记 ----第1章 Elasticsearch概述-01-开篇02-技术选型03-教学大纲-第2章 Elasticsearch入门-04-入门-环境准备05-入门-RESTful & JSON06-入门-Postman客户端工具07-入门-倒排索引08-入门-HTTP-索引-创建09-入门-HTTP-索引-查询 & 删除10-入门-HTTP-…

Linux 调试之 TRACE_EVENT(一)

文章目录前言一、TRACE_EVENT简介二、TRACE_EVENT() 结构2.1 TRACE_EVENT简介2.2 trace_sched_switch示例2.2.1 Name2.2.2 Prototype2.2.3 Arguments2.2.4 Structure2.2.5 Assignment2.2.6 Print2.3 Format file2.3.1 tracing/events/2.3.2 perf2.3.3 bpftrace2.3.4 bcc2.3.5 S…

逻辑回归 鸢尾花分类预测

目录 一&#xff1a;加载数据 二&#xff1a;数据集划分 三&#xff1a;选择算法 四&#xff1a;网格模型 超参数最优解 五&#xff1a;鸢尾花分类预测 六&#xff1a;预测与实际比对 七&#xff1a;完整源码分享 一&#xff1a;加载数据 from sklearn.datasets import…

Jenkins启动项目时报错问题

问题 在工作中使用jenkins进行项目部署启动时遇到问题&#xff0c;项目构建成功但是发布时一直显示时间增加&#xff0c;但是项目本身并没有问题&#xff0c;使用传统方法部署项目也能正常启动。报错如下图所示&#xff1a; 解决方法 是由于jenkins文件中打印日志的问题&am…

PayPal,Stripe,Square轮询支付系统

轮询展示 展示我们轮询的页面 轮询套餐 根据不同的用户和需求&#xff0c;可以选择不同的套餐 普通版 1500元 1年 1个用户 支持Paypal/Stripe 不限制A站个数 不限制B站个数 不限制提交模式 订单管理 物流管理 风控管理 必要的网站数据处理 24小时远程协助 开始…

springcloud服务消费与熔断

今天与大家分享服务消费与熔断&#xff0c;就是说当我们服务消费者转发到服务生产者时&#xff0c;如果有那一步出现了问题或者error&#xff0c;可以进行服务熔断&#xff08;服务降级&#xff09;&#xff0c;为了补救系统问题&#xff0c;不让用户使用时看见error报错信息&a…

《Java》String、StringBuffer、StringBuilder有什么区别?

目录 String StringBuffer StringBuilder 总结 ps&#xff1a;昨天在讨论完String的不可变性之后突然想要做一份总结笔记&#xff0c;总结一下String、StringBuffer、StringBuilder的区别 String String是Java中的基础类&#xff0c;提供了各种构造和对字符串的基本操作&am…

Cocos Creater(3.6.1)开发笔记——Typscript

文章目录项目入门关于cocos creator 3.x关于TypeScript新建项目VS setting json配置屏蔽项事件节点添加脚本&#xff08;事件&#xff09;案例代码素材使用技巧素材组合固定布局&#xff08;类似css&#xff09;项目入门 关于cocos creator 3.x 相当于cocos所有版本的功能的综…

初探MapReduce

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录MapReduce核心思想MapReduce编程模型MapReduce编程实例——词频统计思路1、Map阶段&#xff08;映射阶段&#xff09;2、Reduce阶段&#xff08;归并阶段&#xff09…

VS2019下C#调用C++ DLL详解+数据转换

VS2019下C#调用C DLL详解数据转换 -C#调用OpenCV&#xff08;c的.dll主要有两种常见的方式&#xff1a;托管和非托管两种形式&#xff01; 非托管的形式即是采用[DllImport]的形式&#xff0c;这种形式只能调用的C的函数&#xff0c;适合用于简单的图形处理调用&#xff0c;这也…

正交编码器溢出处理

文章目录1.正交编码器1.1 参数特性1.2 应用范围2.正交编码器使用2.1 溢出问题2.2 中断模式2.3 循环模式延伸1.正交编码器 正交编码器一般指的是增量式光栅&#xff08;磁栅&#xff09;编码器&#xff0c;通常有三路输出信号&#xff0c;A相、B相、Z相&#xff0c;俗称ABZ编码器…

【2022年度系列工作总结】「国内软件质量调查问卷」针对于本年度软件质量分析总结报告

前提背景 针对于目前的软件行业而言&#xff0c;软件的质量目前越来越被大家所在关注&#xff0c;慢慢的QA以及SQA的角色也变得愈加重要。接下来我就针对于我司&#xff08;XXX&#xff09;的相关的实际开发情况对应的【2022年国内软件质量调查问卷】&#xff0c;为大家梳理和…

[附源码]计算机毕业设计Python大学生考勤管理系统论文(程序+源码+LW文档)

该项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程 项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等…

听说Linux基础指令很多?这里都帮你总结好了

✨个人主页&#xff1a; Yohifo &#x1f389;所属专栏&#xff1a; Linux学习之旅 &#x1f38a;每篇一句&#xff1a; 图片来源 &#x1f383;操作环境&#xff1a; CentOS 7.6 阿里云远程服务器 You can’t use up creativity. The more you use, the more you have. 创造力…