【微服务十三】源码深度剖析SpringBoot启动流程中开启OpenFeign的入口(ImportBeanDefinitionRegistrar详解)

本文涉及的产品
服务治理 MSE Sentinel/OpenSergo,Agent数量 不受限
简介: 【微服务十三】源码深度剖析SpringBoot启动流程中开启OpenFeign的入口(ImportBeanDefinitionRegistrar详解)

一、前言

最近在研究OpenFeign源码时,@EnableFeignClients注解中会通过@Import注解导入一个ImportBeanDefinitionRegistrar接口的实现类FeignClientsRegistrar,出于好奇又回头研究了一下SpringBoot启动流程中处理@Import的逻辑,在此记录一下。

我们在SpringBoot启动流程系列聊了以下内容:

1> 《SpringBoot启动流程一》:万字debug梳理SpringBoot如何加载并处理META-INF/spring.factories文件中的信息
2> 《SpringBoot启动流程二》:七千字源码分析SpringApplication构造阶段
3> 《SpringBoot启动流程三》:两万+字图文带你debug源码分析SpringApplication准备阶段(含配置文件加载时机、日志系统初始化时机)
4> 《SpringBoot启动流程四》:图文带你debug源码分析SpringApplication运行阶段和运行后阶段
5> 《SpringBoot启动流程五》:你真的知道SpringBoot自动装配原理吗(两万字图文源码分析)
6> SpringBoot自动装配时做条件装配的原理
7> 源码分析SpringBoot如何内嵌并启动Tomcat服务器的

《SpringBoot启动流程五》:你真的知道SpringBoot自动装配原理吗(两万字图文源码分析);一文中我们聊了在哪里会解析@Import注解,并处理其中自动装配相关的内容(即DeferredImportSelector接口的实现类),本文我们接着讨论如何处理@Import注解导入的ImportBeanDefinitionRegistrar接口实现类。

二、ImportBeanDefinitionRegistrar介绍

ImportBeanDefinitionRegistrar是spring对外提供的动态注册beanDefinition的接口,并且spring内部大多也用该接口动态注册beanDefinition。

  1. ImportBeanDefinitionRegistrar接口的Bean不会直接注册到IOC容器,它的执行时机比较早,发生在SpringBoot启动流程的注册BeanDefinition时;
  2. ImportBeanDefinitionRegistrar接口提供了registerBeanDefinitions(AnnotationMetadata, BeanDefinitionRegistry)供子类重写;

    • 开发者可以直接调用BeanDefinitionRegistry#registerBeanDefinition()方法传入BeanDefinitionName和对应的BeanDefinition对象,直接往Spring临时容器(beanDefinitionMap)中注册。
    • 所谓的Spring临时容器是指:在Spring解析类时会将所有符合注册要求的类放到一个临时容器中,后续执行完BeanPostProcessor、initMessageSource、initApplicationEventMulticaster、onRefresh等操作之后,才会从临时容器中取出所有类,真正注入到Spring容器(singletonObjects)中。

在这里插入图片描述

此外,ImportBeanDefinitionRegistrar 通常和@Import注解配合使用,@Import注解将ImportBeanDefinitionRegistrar的实现类注入到@Import所属根类的ConfigurationClass属性中,在注册跟类的BeanDefinition时,会遍历调用其@Import的所有ImportBeanDefinitionRegistrar接口的 registerBeanDefinitions()方法。

三、ImportBeanDefinitionRegistrar在SpringBoot启动流程中的体现?

建议大家先把SpringBoot启动流程系列看完,然后再看这里,不然有可能会存在一些困惑。

1、处理ImportBeanDefinitionRegistrar的入口

在SpringBoot启动流程中,通过ConfigurationClassParser#doProcessConfigurationClass()解析启动类的注解时,会做@Import注解的process操作,即进入到ConfigurationClassParser#processImports()方法;

具体代码执行流程参考博文:《SpringBoot启动流程五》:你真的知道SpringBoot自动装配原理吗(两万字图文源码分析)

另外debug的项目是我们在OpenFeign系列中的案例(SpringCloud之Feign实现声明式客户端负载均衡详细案例)。

2、将ImportBeanDefinitionRegistrar添加到所属ConfigClass的一个属性上

进入到ConfigurationClassParser#processImports()方法中,就启动类FeignConsumerApplication而言,它直接或间接一共@Import了三个类,分别如下:

在这里插入图片描述

其中FeignClientsRegistrar实现了ImportBeanDefinitionRegistrar接口,FeignClientsRegistrar类图如下:
在这里插入图片描述

下面接着看processImports()方法针对ImportBeanDefinitionRegistrar接口的具体处理逻辑;
在这里插入图片描述

processImports()方法中会判断如果一个类A实现了ImportBeanDefinitionRegistrar接口,会对类A做实例化,并将其存储到当前ConfigClass的一个属性(Map类型的变量importBeanDefinitionRegistrars)中,以在注册ConfigurationClass到Spring容器时,拿出importBeanDefinitionRegistrars中的所有内容,执行每个ImportBeanDefinitionRegistrar的registerBeanDefinitions()方法。

FeignClientsRegistrar而言,会将其添加到启动类FeignConsumerApplication属性中,具体添加过程如下:

在这里插入图片描述

到这里,@Import的内容解析也就结束了,后面会根据@Import解析出的内容再做处理(即:执行ImportBeanDefinitionRegistrar接口方法)。

3、执行ImportBeanDefinitionRegistrar接口方法的时机

解析完所有的candidates候选类之后,会进入到ConfigurationClassBeanDefinitionReader#loadBeanDefinitions(Set<ConfigurationClass>)方法对所有的ConfigurationClass做条件装配、属性处理,然后将相应BeanDefinition注册到Spring中。
在这里插入图片描述

代码执行流程如下:

在这里插入图片描述

代码逻辑解释:

在加载并注册启动类的BeanDefinition时,会将启动类ConfigurationClass下的一些属性进行解析处理,其中就包括对@Import的所有 ImportBeanDefinitionRegistrar接口方法进行执行。

FeignClientsRegistrar而言,其实现的ImportBeanDefinitionRegistrar接口方法执行流程如下:

在这里插入图片描述
这里逻辑就很简单,ImportBeanDefinitionRegistrar接口提供了一个“模板方法”供子类实现。

最后走到FeignClientsRegistrar中,也就进入到了开启OpenFeign的入口

四、后续文章

本篇文章我们讨论了在SpringBoot启动流程中开启OpenFeign的入口,下一篇文章,我们接着讨论OpenFeign如何扫描所有的FeignClient?如何生成FeignClient的代理类?

相关文章
|
14天前
|
Dubbo Java 应用服务中间件
微服务学习 | Springboot整合Dubbo+Nacos实现RPC调用
微服务学习 | Springboot整合Dubbo+Nacos实现RPC调用
|
14天前
|
机器学习/深度学习 负载均衡 Java
【SpringBoot系列】微服务远程调用Open Feign深度学习
【4月更文挑战第9天】微服务远程调度open Feign 框架学习
|
18天前
|
Web App开发 编解码 Java
B/S基层卫生健康云HIS医院管理系统源码 SaaS模式 、Springboot框架
基层卫生健康云HIS系统采用云端SaaS服务的方式提供,使用用户通过浏览器即能访问,无需关注系统的部署、维护、升级等问题,系统充分考虑了模板化、配置化、智能化、扩展化等设计方法,覆盖了基层医疗机构的主要工作流程,能够与监管系统有序对接,并能满足未来系统扩展的需要。
44 4
|
20天前
|
Java API 微服务
【Spring Boot系列】通过OpenAPI规范构建微服务服务接口
【4月更文挑战第5天】通过OpenAPI接口构建Spring Boot服务RestAPI接口
|
16天前
|
运维 监控 安全
云HIS医疗管理系统源码——技术栈【SpringBoot+Angular+MySQL+MyBatis】
云HIS系统采用主流成熟技术,软件结构简洁、代码规范易阅读,SaaS应用,全浏览器访问前后端分离,多服务协同,服务可拆分,功能易扩展;支持多样化灵活配置,提取大量公共参数,无需修改代码即可满足不同客户需求;服务组织合理,功能高内聚,服务间通信简练。
31 4
|
17天前
|
存储 Java 时序数据库
【SpringBoot系列】微服务监测(常用指标及自定义指标)
【4月更文挑战第6天】SpringBoot微服务的监测指标及自定义指标讲解
|
2天前
|
传感器 人工智能 前端开发
JAVA语言VUE2+Spring boot+MySQL开发的智慧校园系统源码(电子班牌可人脸识别)Saas 模式
智慧校园电子班牌,坐落于班级的门口,适合于各类型学校的场景应用,班级学校日常内容更新可由班级自行管理,也可由学校统一管理。让我们一起看看,电子班牌有哪些功能呢?
41 4
JAVA语言VUE2+Spring boot+MySQL开发的智慧校园系统源码(电子班牌可人脸识别)Saas 模式
|
10天前
|
缓存 Java 开发者
10个点介绍SpringBoot3工作流程与核心组件源码解析
Spring Boot 是Java开发中100%会使用到的框架,开发者不仅要熟练使用,对其中的核心源码也要了解,正所谓知其然知其所以然,V 哥建议小伙伴们在学习的过程中,一定要去研读一下源码,这有助于你在开发中游刃有余。欢迎一起交流学习心得,一起成长。
|
10天前
|
Java Docker 微服务
|
12天前
|
JavaScript Java 大数据
springboot高精度UWB定位系统源码
UWB (ULTRA WIDE BAND,) 技术是一种无线载波通讯技术,它不采用正弦载波,而是利用纳秒级的非正弦波窄脉冲传输数据,因此其所占的频谱范围很宽。UWB定位系统依托在移动通信,雷达,微波电路,云计算与大数据处理等专业领域的多年积累,自主研发,开发并产业化的一套UWB精确定位系统,最高定位精度可达10cm,具有高精度,高动态,高容量,低功耗的优点。
18 0