Spring Boot自动装配bean到IOC容器的实现

news/2025/3/22 1:51:15/文章来源:https://www.cnblogs.com/liftsail/p/18231005

前言


Spring Boot能帮助我们Java开发者快速开发基于Spring框架的应用,除了其作为依赖管理好帮手的一众Spring-Boot-Starter之外,其自动装配(Auto Configure)特性也起到了非常重要的作用。那么Spring Boot是如何实现自动装配的呢?本文将结合源码去讲解其原理。

版本信息


  • spring-boot-autoconfigure-2.7.5.jar
  • spring-context-5.3.23.jar
  • dubbo-3.1.1.jar
  • dubbo-spring-boot-autoconfigure-3.1.1.jar

前置知识


Spring框架里最重要的模块莫过于IoC容器,流畅阅读本文的前提是读者有IoC容器的基本概念。
我们先来梳理一些概念,Spring IoC容器里的所有组件(Component,构建完整应用的基本单元)都被称为Bean。Spring IoC容器不是神,当想要帮助其使用者实例化某个具体的Bean时,需要一些额外的信息才能做到,这些额外的信息被称为Meta-data(元数据或元信息),例如多个构造器选择哪个、构造器参数信息、是否需要Autowire处理等等信息,在Spring框架里,其被抽象为BeanDefinition接口,大概长下面这个样子。

就像如果我们要解析JSON字符串需要调JSON解析库把其转成JSON对象再从里获取你需要的信息(数据)一样,创建实例所用的这些个BeanDefinition信息是不会自己跑到Spring IoC容器里的,这需要Spring IoC容器自己去收集,收集BeanDefinition信息是Spring IoC容器的几大主要工作之一。那么Spring框架是如何收集这些信息的呢?

Spring框架如何收集BeanDefinition信息?

既然要收集信息,就不得不提信息载体,信息载体是承载信息(数据)的东西,但凡一个物体能表示1bit的信息都能被视为信息的载体,可见信息的载体有很多种,就例如各种格式的文本文件、序列化后的二进制文件、Java内存里的(Java注解、类名、方法名、参数名、参数类型)等等都是信息的载体。那么相信大家已经猜到了,Spring收集BeanDefinition信息的方式大家至少可以有这么几种:

  • XML配置:Spring所谓的XML config方式,通过XML文本文件存储信息。
  • Java配置:Spring所谓的Java config方式,利用反射API收集注解、类名、方法名、参数名、参数类型携带的信息。

Java配置又可以细分成几种:

  • 如@Component、@Service、@Controller之类的通常是Spring通过反射API和缺省信息去收集BeanDefinition信息。
  • 如@Configuration之类的则是由开发者自主装配Bean。Spring不需要费太大力气便能利用广大开发者写的Bean方法去实例化某个Bean。

除开上面两个,还有如ImportSelector接口、ImportBeanDefinitionRegistrar接口这两种方式:

  • ImportBeanDefinitionRegistrar接口:模块开发者直接向IoC容器里注册BeanDefinition,如dubbo里就用了这种方式。
  • ImportSelector接口:递归地注册ImportSelector#SselectImports方法所发现的所有ImportSelector、ImportBeanDefinitionRegistrar、@Configuration类相关的BeanDefinition。

虽然再细分ImportSelector还能分出DeferredImportSelector,不过这不在本文的讨论范畴之内,咱们先忽略它。

Spring Boot 自动装配的原理


Spring Boot自动装配本质就是向IoC容器提供BeanDefinition的过程。其用到了我们上述的四种Java Config中的后三种。

  • ImportSelector接口
  • ImportBeanDefinitionRegistrar接口
  • @Configuration类

Spring框架的Context核心模块提供了这些功能

上面提到的分三类的处理方式并不是Spring Boot提供的,而是Spring Context提供的。
你可以在下面方法里看到其处理的逻辑:

Spring-Context-5.3.23.jar文件的
org.springframework.context.annotation.ConfigurationClassParser类的
processImports方法

private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,Collection<SourceClass> importCandidates, Predicate<String> exclusionFilter,boolean checkForCircularImports) {/* 省略 */for (SourceClass candidate : importCandidates) {if (candidate.isAssignable(ImportSelector.class)) { // Candidate class is an ImportSelector -> delegate to it to determine imports/* 省略 */ } else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {// Candidate class is an ImportBeanDefinitionRegistrar ->// delegate to it to register additional bean definitions/* 省略 */} else {// Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar ->// process it as an @Configuration class/* 省略 */}}/* 省略 */
}

Spring Boot则利用了Spring Context提供的功能来实现自动装配。

@EnableAutoConfiguration:Spring Boot开启自动装配特性的注解

想要Spring Boot开启自动装配特性,我们是需要在程序入口类使用@EnableAutoConfiguration注解来开启自动装配功能,也许大家没怎么见过这个注解,不过一般使用了组合注解@SpringBootApplication的话就是等于开启了@EnableAutoConfiguration的,@SpringBootApplication注解的定义如下:

@EnableAutoConfiguration本身也是一个组合注解,定义如下:

@Import(AutoConfigurationImportSelector.class)则是其最重要的部分,不难看出其核心是一个我们上面提到过的ImportSelector,@Import注解是向IoC容器里引入一个Bean,这里就引入了AutoConfigurationImportSelector类。

Spring Boot提供的AutoConfigurationImportSelector类干了什么?

相信大家都对spring.factories文件或多或少都有耳闻。对,你猜的没错,简单来AutoConfigurationImportSelector类主要干了两件事

  1. 利用SpringFactoriesLoader类从ClassPath上所有的META-INF/spring.factories文件读取上述三种自动配置类的信息(类名)。
  2. 利用ImportCandidates类从ClassPath上所有的META-INF/spring/org.springframework.boot.autoconfiguration.AutoConfiguration.imports文件里读取上述三种自动配置类的信息(类名)。
  3. AutoConfigurationImportSelector类种利用这两个类的源码如下,第二种方式是较新的,而spring.factories文件的方式则是较老的一种实现。目前在笔者的spring boot 2.7.5版本里是两者都支持的(也就是提供了向下兼容性)。可以看到下方源码中,先调用了SpringFactoriesLoader,再调用了ImportCandidates。

AutoConfigurationImportSelector支持的两类文件长什么样?


在上一节我们提到了AutoConfigurationImportSelector类支持两类文件来做扩展,分别是:

  • 较老的META-INF/spring.factories文件
  • 较新的META-INF/spring/org.springframework.boot.autoconfiguration.AutoConfiguration.imports文件

1. META-INF/spring.factories文件

第一个是较老的META-INF/spring.factories文件,其本质是个Properties格式的文本文件。内容就是KEY=VALUE。
就比如说我们看一下dubbo-spring-boot-autoconfigure-3.1.1.jar里的这个文件就长这样:

2. META-INF/spring/org.springframework.boot.autoconfiguration.AutoConfiguration.imports文件

第二个是比较新的META-INF/spring/org.springframework.boot.autoconfiguration.AutoConfiguration.imports,其就是个普通的换行符分割文本文件。
我们看一下spring-boot-autoconfigure-2.7.5.jar里的这个文件长这样:

文件内容

两种文件的内容普遍都是@Configuration类的全名(包名+类名),这里的数据本质是字符串,读到内存里还是需要利用反射API转换成Class<?>实例再开始使用的,就是由ConfigurationClassParser$DeferredImportSelectorHandler的processGroupImports方法来实现的。可以看到内部调用了我们先前提到的processImports方法。

反射API具体使用的地方就是上面代码里的调用asSourceClass方法了:

结语


通过源码分析,我们可以看到Spring Boot利用了Spring Context提供的加载机制,其先利用@Import把自身最关键的组件AutoConfigurationImportSelector引入到容器里,并且引入ImportSelector是会递归引入AutoConfigurationImportSelector在两种文件里找到的所有的类,也是这种动态地加载所有这两类文件的机制是Spring Boot自动装配实现扩展性的核心。使得其他项目、组件的开发者可以利用这个扩展机制(如编写自己的spring.factories文件、@Configuration类等)去支持或叫实现自动装配。但不难看出Spring Boot虽然实现了自动装配,但实际的装配工作(@Configuration类、ImportSelector、ImportBeanDefinitionRegistrar的编码工作)还是需要由对应的项目开发者去实现的,比如dubbo就是自己实现的相应的spring boot自动装配类。

转载自https://blog.csdn.net/ToraNe/article/details/127956347

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

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

相关文章

有哪些免费方法可以将PDF转成PPT?

有时候我们在制作文件时,新建的PPT文档是空白页比较单调,会去网上下载一些模板,而下载后的文档多是PDF格式,必须转换为PPT格式,以便使用自己的文档。所以pdf转ppt怎么转换免费呢?下面一起来看看pdf转ppt这些方法吧。 方法一、修改文件拓展名 小伙伴们平时打开文件的时候,…

idea打包运行后显示,没有主清单属性

一、问题现象idea打包成jar包,运行后显示,没有主清单属性!二、问题分析主要原因如下:1. 缺少了项目maven打包插件 spring-boot-maven-plugin。2. 没有指定具体的项目的Main方法入口或启动类。三、解决方法 (一)方法1 1、查看项目打包的pom.xml文件中,并添加配置如下:&l…

zabbix监控域名到期时间

# 获取证书过期时间脚本cat /etc/zabbix/scripts/base/check-http-expire.sh #!/bin/bash host=$1 #end_date=`whois -H $host|grep "Registry Expiry Date"|awk {print $NF}` end_date=`whois -H $host|egrep "Registry Expiry Date|Expiration Time"|a…

字符串的应用---合并

准备: public class Employee{ public int Id { get; set; } public string Name { get; set; } public double Salary { get; set; } } public class Seat { public int Id { get; set; } publ…

pycharm创建项目后修改默认的app

在pycharm里面创建django项目后,会自动创建一个与项目名称相同的app,该app是可以修改的,但是修改后需要修改配置文件settings.py中的配置项ROOT_URLCONF

Apline部署K3s的Agent

介绍了在Alpine-Linux上部署K3s-Agent之前我们在Ubuntu上部署了K3s的Server节点(传送门),这次我们加入两台K3s的Agent节点搭建一个K3s的3节点工作环境。 需要准备好网络环境,确保三台VM之间是可以ping通的,设置好固定IP和主机名 实验环境的IP列表Hostname IPubuntu22 192.…

关于bandgap中极性的判断

bandgap的中运放的正负相位都有连接,且前馈系数一般相同,则需要使得负反馈系数大于正反馈系数,环路才稳定。 对于不同类型的bandgap,其正负相位一般连接不同。 https://blog.csdn.net/weixin_39889337/article/details/112767268

基于mac-vlan的网络准入控制方案

网络拓扑图如下:SW1 配置vlan 10 20 30 4000 #创建vlan interface GigabitEthernet1/0/1 #进入接口 port link-type hybrid #接口模式设为hybrid port hybrid vlan 10 20 30 4000 untagged #vlan 10 20 30 4000数据包没有tag port hybrid pvid vl…

工具:一键采集 平台:TB+PDD+JD...

电商商品数据集通常是指收集自电子商务平台的商品信息的结构化数据集合。这些数据包括但不限于商品名称、价格、描述、用户评价、分类标签、卖家信息、销售量、库存量、图片链接等。数据集可以由电商平台公开提供,也可以通过网络爬虫等技术手段获得,并且经常会用于机器学习、…

Stratix V FPGA系列:5SGXEBBR3H43I3G、5SGXEBBR1H43C2G、5SGXEBBR2H43I2G为带宽应用而打造,降低了系统成本和功耗

Stratix V GX FPGA芯片提供340K逻辑单元和集成最大12.5 Gbps传输速度的收发器Stratix V系列 Stratix V FPGA采用新的存储器体系结构,降低延时,高效实现FPGA业界最好的系统性能。Stratix V FPGA为网络设备生产商提供存储器接口解决方案,支持在互联网上迅速有效的传送视频、语…

NCHU-软件学院-232019班-23201125-罗伊鑫-第二次Blog

前言 本次Blog总结三次题目集的7-1题目的知识点、题量、难度等情况,以及写完后的错误总结和自我思考。 1.知识点 三次题目集都对于类的设计的提前规划好有着必要的需求,还有就是对于继承与多态的合理的使用。接着就是对于正则表达式的使用的检测,然后就是要有清晰的逻辑编程…

Qt开发技术:Q3D图表开发笔记(四):Q3DSurface三维曲面图颜色样式详解、Demo以及代码详解

前言qt提供了q3d进行三维开发,虽然这个框架没有得到大量运用也不是那么成功,性能上也有很大的欠缺,但是普通的点到为止的应用展示还是可以的。  其中就包括华丽绚烂的三维图表,数据量不大的时候是可以使用的。  前面介绍了基础的q3d散点图、柱状图、三维曲面图,本片深…