Feign源码分析-接口如何发现并生成代理类

简介: Feign源码分析-接口如何发现并生成代理类

1写作目录


之前自己写过一个RPC框架demo,遇到两个问题没有解决。


在consumer端怎么找到被代理的接口呢?

比如用这个@FeignClient注解,正常情况下Spring是识别不到的,那是怎么识别到的呢?


接口如何代理呢?

之前的动态代理和静态代理都是先生成一个类,然后在去代理,但是在consumer端是没有接口实现类的,那怎么实现代理的呢?


因为解决这两个问题,也因为一些机缘巧合,看了部分Feign的源码,从而理解了这其中的逻辑,下面给大家分析并记录一下这个问题。


2前提


了解SpringBoot的自动装配原理,否则跟不上


3环境搭建


下载地址:https://github.com/cbeann/SpringCloudDemoHoxton


如下图所示,其中Service层就是Feign接口,Controller层调用Service的Feign接口


0.png


4 源码分析


4.1如何找到@FeignClient标注的接口


4.1.1添加注解引入目标类


在consumer端一般会加@EnableFeignClients注解,其实这是一个复合注解,点进去看一下可以发现


@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(FeignClientsRegistrar.class)


引入了FeignClientsRegistrar.class这个类并加载到IOC容器中。然后就会到达registerBeanDefinitions方法并在该方法里调用registerFeignClients方法


//FeignClientsRegistrar.java
@Override
  public void registerBeanDefinitions(AnnotationMetadata metadata,
      BeanDefinitionRegistry registry) {
    registerDefaultConfiguration(metadata, registry);
    registerFeignClients(metadata, registry);
  }


4.1.2寻找代理接口


1)首先获取带有EnableFeignClients注解的启动类的包路径


//FeignClientsRegistrar###registerFeignClients
        Set<String> basePackages;
    Map<String, Object> attrs = metadata
        .getAnnotationAttributes(EnableFeignClients.class.getName());
    basePackages = getBasePackages(metadata);


2)然后获取.class文件并解析。

下图为ClassPathScanningCandidateComponentProvider##scanCandidateComponents方法。


如果找到有@FeignClient注解的则解析为ScannedGenericBeanDefinition


01.png


3)然后对上面的每一个ScannedGenericBeanDefinition进行二次封装

此时到达FeignClientsRegistrar的registerFeignClient方法,把每一个ScannedGenericBeanDefinition封装为AbstractBeanDefinition,注意,此时的class类型为FeignClientFactoryBean.class


02.png


4)此时我们就明白了,Spring原来是通过解析.class文件获取@FeignClient注解的interface并解析为类型为FeignClientFactoryBean.class的BeanDefinition,剩下的就是Bean的生命周期了。


4.2FeignClientFactoryBean的生命周期


我们先看一下FeignClientFactoryBean类的继承关系


class FeignClientFactoryBean
    implements FactoryBean<Object>, InitializingBean, ApplicationContextAware


这个类继承了FactoryBean接口,那么在Bean的生命周期里肯定会调用FactoryBean的getObject方法,此时我们就是在FactoryBean的getObject方法上打断点,从这里开始debug


00.png


因为这是Bean的生命周期(了解Bean的生命周期并从调用栈可以看出),所以我们一直从上面的那个地方跟命令是return的方法,一直跟到ReflectiveFeign的newInstance方法,如下图所示,有没有发现,这个地方是不是似曾相识(不相识的话说明动态代理不熟)?


000.png


5总结


Feign是通过扫描.class文件定位到标有@FeignClient注解的类的,然后解析为类型为FeignClientFactoryBean.class的BeanDefinition,然后执行Bean的生命周期,最后调用FeignClientFactoryBean的getObject方法进行动态代理。

拓展:其实也可以通过BeanPostProcessor去实现上面的功能,当然不让上面的完美


其实远程调用有一个统一面临的问题,就是你是不知道远程调用类是什么类型的,那么怎么对这个类执行Bean的生命周期呢?或者换换句话说,BeanDefinition里面的类是哪个类呢?如果要做到统一,则可以使用FactoryBean接口,让类的创建发生延迟,其实Dobbo的源码中也是通过FactoryBean实现的。


目录
相关文章
|
Shell Linux API
【Shell 命令集合 备份压缩 】Linux 解压缩文件 unzip命令 使用指南
【Shell 命令集合 备份压缩 】Linux 解压缩文件 unzip命令 使用指南
755 0
|
IDE 数据处理 开发工具
垃圾分类模型训练部署教程,基于MaixHub和MaixPy-k210(1)
我的准备 Maix duino开发板一块(含摄像头配件) Type-c数据集一根
660 0
|
数据采集 存储 JavaScript
如何使用Puppeteer和Node.js爬取大学招生数据:入门指南
本文介绍了如何使用Puppeteer和Node.js爬取大学招生数据,并通过代理IP提升爬取的稳定性和效率。Puppeteer作为一个强大的Node.js库,能够模拟真实浏览器访问,支持JavaScript渲染,适合复杂的爬取任务。文章详细讲解了安装Puppeteer、配置代理IP、实现爬虫代码的步骤,并提供了代码示例。此外,还给出了注意事项和优化建议,帮助读者高效地抓取和分析招生数据。
540 0
如何使用Puppeteer和Node.js爬取大学招生数据:入门指南
|
11月前
|
人工智能 JSON Java
Sring.ai生成图片的功能---OpenAiImageClient
随着大模型的升级迭代,现在越来越多的人都开始接入API接口了,尤其是JAVA的同学们,上一篇文章介绍了,从零搭建一个环境,用于调用openai的key,进行访问AI接口,进行一些对话的功能,本篇文章主要介绍生成图片的接口。希望可以帮助到正在学习spring.ai的同学一些参考。
526 2
Sring.ai生成图片的功能---OpenAiImageClient
|
消息中间件 Java Kafka
Spring Boot与Kafka的集成应用
Spring Boot与Kafka的集成应用
|
SQL 网络安全 数据库
GBase 8a集群V8客户端gccli适配欧拉操作系统绕行方案分析
GBase 8a集群V8客户端gccli适配欧拉操作系统绕行方案分析
|
监控 安全 数据库
深入探究:GitLab数据备份与还原的高效策略
【10月更文挑战第19天】 在现代软件开发中,GitLab作为一个强大的代码管理和协作平台,其数据备份与还原是保障项目安全和连续性的关键环节。本文将深入探讨GitLab数据备份与还原的高效策略,确保在数据丢失或损坏的情况下,能够快速恢复GitLab实例。
527 2
|
Web App开发 Kubernetes 数据可视化
Kubernetes Dashboard 可视化插件部署 博主亲自实践可用
Kubernetes Dashboard 可视化插件部署 博主亲自实践可用
313 0
|
Cloud Native Java Go
解决Nacos配置刷新问题: 如何启用配置刷新功能以及与`@RefreshScope`注解的关联问题
解决Nacos配置刷新问题: 如何启用配置刷新功能以及与`@RefreshScope`注解的关联问题
1716 0
|
API
Calendar常用API
Calendar常用API
289 1