SpringBoot自动配置原理

本文详细解读了SpringBoot如何通过@SpringBootApplication简化配置,从启动类到自动装配的流程,涉及@ComponentScan、@Import、AutoConfigurationImportSelector等关键概念。深入解析了配置类处理、自动装配的两个主要步骤和延迟导入机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

SpringBoot基于Spring框架发展而来,是Spring框架的自动化配置版本。使用Spring框架免不了要基于XML配置文件开发,要配置web.xml,dataSource,TransactionManager,SqlSessionFactory,SpringMVC的配置,MyBatis的配置等等。

刚开始入手SpringBoot时,很神奇配置一个application.yml就可以跑了,那以往的繁琐各种Bean的配置哪去了?

其实SpringBoot对于集成的各路框架做了自动配置的机制,每个框架都有了默认的配置,基于自动配置原理封装了Bean托管给了IOC容器。SpringBoot提供了各种starter依赖,就是第三方框架集成SpringBoot的Jar包,其中 spring-boot-starter-xxxx 是SpringBoot官方提供的第三方框架集成依赖,xxxx-spring-boot-starter是第三方提供的集成进SpringBoot的依赖。

SpringBoot应用的启动类上都会注解一个@SpringBootApplication,这个注解中有一个@EnableAutoConfiguration注解,

这个注解又用@Import导入了个 AutoConfigurationImportSelector 类,这是个什么东东?

看它的注释会了解到是专门处理@EnableAutoConfiguration注解的处理类。

SpringBoot 2.2.0 自动装配的调用时序:

SpringBootApplication.run() -> SpringApplication.refersh() -> AbstractApplicationContext.refersh() -> ...... ->

AbstractApplicationContext.invokeBeanFactoryPostProcessor()这里是调用BeanFactoryPostProcessor,也是在这里会拿到配置类处理器 ConfigurationClassPostProcessor执行。

ConfigurationClassPostProcessor.processConfigBeanDefinitions() -> ConfigurationClassParser.parse() -> this.deferredImportSelectorHandler.process() ->...... -> 中间省一段调用逻辑,来到AutoConfigrationImportSelector.process(AnnotationMetadata, DeferredImportSelector)

到这里我们可以看到有 注解元数据对象,这个元数据其实就是启动类ApplicationContext上的注解,左下角是调用栈可以查看调用链路。

从一开始启动类因为注解了@SpringBootApplication就被当做配置类,传递到配置类处理器ConfigurationClassPostProcessor。

调用CongigurationClassParser.parse()开始作为入口,开始解析启动类包下的托管bean,通过@ComponentScan扫描指定路径的托管bean,以及自动装配的核心AutoConfigurationSelectorImport。实际的解析配置类的工作是ConfigurationClassParser.parse()中做的。

从这里看自动装配可以被分为2大部分:

  • 处理@ComponentScan,扫描启动类包下所有声明式bean
  • 处理@Import,根据@Conditional系列注解,注册bean

@ComponentScan注解扫描

ConfigurationClassParser.processConfigurationClass()函数被反复调用,第一行就会判断此配置类是否应该被忽略,就是根据@Conditional机制判断。

doProcessConfigurtionClass()是真正解析配置类的地方,首先解析@ComponentScan注解。

上面的@ComponentScan注解处理完毕后,启动类本身的指定Jar包扫描路径下的托管bean就全部被封装成BeanDefinition对象加入configurationClasses集合中。等待下一阶段解析BeanDefinition,实例化Bean,注册到BeanRegistry中。

处理@Import注解

我们最开头分析的AutoConfigurationImportSelector对象,是自动装配的关键对象,现在就是要通过它去加载其它自动配置类的时候了。代码来到 processImports(configClass, sourceClass, getImports(souceClass), true) ,这个函数就是处理所有配置类@Import注解。getImports() 会拿到AutoConfigurationImportSelector传入进去。

下图,当前配置类就是启动类,遍历importSelector,经过 deferredImportSelectorHandler.handle() 处理,它会被加入到deferredImportSelectors这个容器中,等到当前的启动类被解析完后,线程回去执行 this.deferredImportSelectorHandler.process();

这里需要说一下:

这里的解析配置类的逻辑其实挺绕的,ConfigurationClassPraser.parse()开始到doProcessConfigurationClass()是真正解析配置类的地方。遍历 importCandidates中,如果导入类又是一个ImportSelector,那么分类讨论,如果是deferred的即延迟导入的,就先加入deferredImportSelectors中,等到当前配置类解析完后,执行this.deferredImportSelectorHandler.process(); 才去处理延迟导入器。

当线程执行 this.deferredImportSelectorHandler.process(); 遍历容器中的延迟导入器,其中AutoConfigurationImportSelector就会来到下图的位置,会拿到所有classpath下META/spring.factories文件的配置类

继续来到 getCandidateConfigurations(metadata, attributes),在这里就是去处理 starter 组件在META/spring.factories配置的组件自动装配类对象的入口函数。用的是AppClassLoader去加载classpath下的文件。

这里提一下,SpringFactoriesLoader.loadFactoryNames()这一步会从缓存中直接取到EnableAutoConfiguration这个FactoryName为Key的列表。列表中存了配置类全限定名。在SpringBoot启动时,创建SpringApplication对象时就会去加载SpringBoot jar包下的所有spring.factories文件存入缓存。                    

经过读取META/spring.factories配置文件中配置类,就拿到了这些配置类的全限定路径,下一步是去加载class,解析成BeanDefinition

拿到上图的所有自动配置类后,要去解析这些配置类,当然这些配置类中可能又引入了其它托管bean,所以遍历再去processImports()

解析完当前启动类的所有配置类之后,就去加载这些配置类,封装成BeanDefintion

最后一步reader.loadBeanDefinitions()和IOC原理 Bean的加载 衔接,可看:

Spring IOC原理 Bean实例化、依赖注入和循环依赖解决

参考文章:

深入理解SpringBoot核心原理(一)--------启动机制(starter机制) - 掘金深入理解SpringBoot核心原理(一)--------启动机制(starter机制)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值