首页 > 其他分享 >Spring Boot自动装配bean到IOC容器的实现

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

时间:2024-06-04 16:00:05浏览次数:21  
标签:装配 Spring Boot ImportSelector 信息 bean spring

前言


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

标签:装配,Spring,Boot,ImportSelector,信息,bean,spring
From: https://www.cnblogs.com/liftsail/p/18231005

相关文章

  • Spring Boot 3.x集成FastDFS记录
    最近在做一个课程,需要用讲一下SpringBoot使用文件上传的功能,选择了FastDFS作为文件存储OSS。SpringBoot是最新的3.3.0版本,JDK版本是17,中间有一些坑,下面记录一下。<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</......
  • 基于SpringCloudAlibaba+Sharding-JDBC的微服务的分库分表设计
    胡弦,视频号2023年度优秀创作者,互联网大厂P8技术专家,SpringCloudAlibaba微服务架构实战派(上下册)和RocketMQ消息中间件实战派(上下册)的作者,资深架构师,技术负责人,极客时间训练营讲师,四维口袋KVP最具价值技术专家,技术领域专家团成员,2021电子工业出版社年度优秀作者,获得2023电......
  • 基于SpringBoot的英语单词小程序的设计与实现(期末大作业)+附源码+数据库
    摘要随着经济的不断发展与进步,语言的全球化慢慢的变成现今世纪非常重要的一种发展趋势。本文针对大学生在校阶段开发了一个基于SpringBoot的英语等级助考系统,通过线上小程序学习的方式,减少学生学习时间、降低学生学习压力、增强学习效果。该系统采用微信开发工具和基于SpringB......
  • Springboot计算机毕业设计医院门诊小程序【附源码】开题+论文+mysql+程序+部署
    本系统(程序+源码)带文档lw万字以上 文末可获取一份本项目的java源码和数据库参考。系统程序文件列表开题报告内容研究背景随着移动互联网技术的迅猛发展,人们对于医疗服务的便捷性和高效性提出了更高要求。传统医院门诊流程复杂、耗时较长,已无法满足现代患者快速就医的需求......
  • Springboot计算机毕业设计医院排班&预约小程序【附源码】开题+论文+mysql+程序+部署
    本系统(程序+源码)带文档lw万字以上 文末可获取一份本项目的java源码和数据库参考。系统程序文件列表开题报告内容研究背景在现代医疗服务体系中,医生与患者的对接效率直接影响着医院的运营效率和患者的就医体验。传统的排班与预约方式往往存在信息更新不及时、预约流程繁琐......
  • JAVA计算机毕业设计基于Web的小学学科数字教学资源管理系统的开发与设计(附源码+spring
    本系统(程序+源码)带文档lw万字以上 文末可获取一份本项目的java源码和数据库参考。系统程序文件列表开题报告内容研究背景在信息化时代的浪潮下,教育领域正经历着深刻的变革。随着互联网技术的飞速发展,数字教学资源已成为小学学科教育中不可或缺的一部分。然而,当前许多小学......
  • JAVA计算机毕业设计基于web的校园互助系统设计(附源码+springboot+开题+论文)
    本系统(程序+源码)带文档lw万字以上 文末可获取一份本项目的java源码和数据库参考。系统程序文件列表开题报告内容研究背景随着互联网技术的迅猛发展和普及,校园生活也逐渐步入了数字化、网络化的新阶段。在这样的背景下,校园内的信息交流和互助需求日益增长。然而,传统的校园......
  • Bootstrap框架
    原文链接:https://blog.csdn.net/2301_80068547/article/details/134619359一、Bootstrap简介Bootstrap来自Twitter(推特),是目前最受欢迎的前端框架。Bootstrap是基于HTML、CSS和JavaScript的,它简洁灵活,使得Web开发更加快捷。中文官网:https://www.bootcss.com/官网:http......
  • Spring boot - 仅当 JavaMailSender 豆存在时自动配置
    我相信这应该很简单,但我想不通。我有一个这样的配置类:@Configuration@AutoConfigureAfter(MailSenderAutoConfiguration.class)公共类MyMailConfiguration{@Bean@ConditionalOnBean(JavaMailSender.class)publicMyMailermyMailer(JavaMailSender......
  • OpenTelemetry agent 对 Spring Boot 应用的影响:一次 SPI 失效的案例
    背景前段时间公司领导让我排查一个关于在JDK21环境中使用SpringBoot配合一个JDK18新增的一个SPI(java.net.spi.InetAddressResolverProvider)不生效的问题。但这个不生效的前置条件有点多:JDK的版本得在18+SpringBoot3.x还在额外再配合使用-javaagent:openteleme......