【源码分析SpringBoot的自动配置原理】


前言

众所周知,使用Spring框架进行项目开发时,起初要编写各种xml文件,用来定义bean信息,比较繁琐;后面可以通过注解的方式(javaBean方式)轻松了许多,但是如果与其他第三方组件进行整合时,还是需要进行一些配置,也是比较麻烦。发布代码时,还要将项目打包成war包,放到Tomcat等Servlet容器中,启动Servlet进行web访问。而SpringBoot的出现可以让这些繁琐的工作简化,通过引入具体组件的starter,在配置文件中进行简单的配置,就可以轻松使用这些组件;这些都得益于SpringBoot的自动配置,下面具体分析它时如何工作的!!!


一、SpringBoot启动入口

在main方法所在的主类上会标注@SpringBootApplication这么一个注解,它等同于@SpringBootConfiguration@EnableAutoConfiguration@ComponentScan这3个注解的组合

  • @SpringBootConfiguration:其实就是@Configuration注解,表示当前类是一个配置类
  • @EnableAutoConfiguration:开启自动配置,标注此注解Spring会扫描获取各个xxxAutoConfiguration配置类,完成对spring-boot-starter-xxx相关组件注入
  • @ComponentScan :扫描指定的包及其子包下的标注@Component的类注入spring容器中,开发中常用的@Controller@Service@Repository其实都是@Component;如果没写具体包名,则扫描标注了@ComponentScan的类所在包及其子包

二、@EnableAutoConfiguration

1. @EnableAutoConfiguration是啥?

@EnableAutoConfiguration其实就是包含了@Import,而@Import这个注解的功能是将一个类导入到Spring容器中,使这个类成一个Spring的bean,而导入的这个类,可以是:

  1. 普通简单类: 直接导入Spring容器,成为一个bean
  2. 实现DeferredImportSelector接口: 延迟的ImportSelector,它是ImportSelector接口的子接口,作用和ImportSelector接口一样
  3. 实现ImportSelector接口:它的作用是将一组类注入到Spring容器中,此接口有一个方法selectImports,返回类的全限定类名数组,将这些类注入到Spring容器中
  4. 实现ImportBeanDefinitionRegistrar接口:它的主要功能是注册BeanDefinition,Spring再根据BeanDefinition实例化成bean,
    这里导入的是AutoConfigurationImportSelector类,它实现了DeferredImportSelector接口

2. @EnableAutoConfiguration 执行时机

@EnableAutoConfiguration的执行时机,即@Import的执行时机,是在SpringBoot启动流程中,刷新上下文时调用的(了解SpringBoot的启动流程

在这里插入图片描述

内部调用AbstractApplicatoinContext#refresh方法,再调用invokeBeanFactoryPostProcessors方法,这属于Spring的范畴了

在这里插入图片描述

调用内部的invokeBeanDefinitionRegistryPostProcessors方法,主要是调用BeanDefinitionRegistryPostProcessor接口的postProcessBeanDefinitionRegistry方法,这里会获取到处理@Import注解的类ConfigurationClassPostProcessor,它正好实现了接口BeanDefinitionRegistryPostProcessor,进而调用ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry方法

在这里插入图片描述

postProcessBeanDefinitionRegistry内部再调用processConfigBeanDefinitions方法,其方法内部先是获取所有的BeanDefinition,循环找到所有配置类(标注了@Configuration的类),刚好@SpringBootApplicaiton内部含有@Configuration,所以主类就是配置类

在这里插入图片描述

接下来就会创建ConfigurationClassParser,这个对象是用来解析配置类的,循环调用这个对象的parse方法进行解析配置类,因为配置类可能有多个

在这里插入图片描述

进入parse方法,继续调用parse重载方法

在这里插入图片描述

进一步调用了processConfigurationClass方法,遍历调用doProcessConfigurationClass方法,为啥遍历?因为当前配置类可能有父类,对父类再处理,这里主类没有父类所以只执行一次
注意:解析过的配置类都会放到configurationClasss这个集合,后面会取出,对它们进行加载到Spring容器中

在这里插入图片描述

doProcessConfigurationClass 就是真正做处理的方法,里面就包含对@Import的解析,解析方法为processImports,注意传参里面的getImports(sourceClass)方法,它获取导入的类,这里即获取到了AutoConfigurationImportSelector

在这里插入图片描述

进入processImports方法,对AutoConfigurationImportSelector进行处理,它是DeferredImportSelector接口实现类,所以调用了deferredImportSelectorHandler#handle方法,这里理解成将它保存起来后续处理,为啥后续处理?从这个接口的名字可以理解,Deferred(延迟的),因为它会在ImportSelector接口处理完之后再处理,而我们一般都是实现ImportSelector接口,完成对组件的配置,而SpringBoot的自动配置实现了DeferredImportSelector接口,也就是说SpringBoot对组件的配置是在我们配置之后的,这就是为啥,我们定义了组件之后,SpringBoot对该组件的配置不生效的原因

在这里插入图片描述

而如果只是实现了ImportSelector接口,会立即执行selectImports方法获取到类名数组,再次递归调用processImports为啥要递归调用?因为import进来的类,有可能也刚好实现了上面3个接口,所以需要递归处理

3. AutoConfigurationImportSelector执行流程

上面讲到AutoConfigurationImportSelectorDeferredImportSelectorHandler(ConfigurationClassParser的内部类)调用handle方法保存起来,里面对其进行封装成了一个DeferredImportSelectorHolder对象,并添加到了一个集合中

在这里插入图片描述

而它的执行时机是在ConfiurationClassParser#parse方法的最后,调用DeferredImportSelectorHandler#process方法

在这里插入图片描述

在process方法中,主要对其进行分组处理,创建DeferredImportSelectorGroupingHandler对象,(理解成分组对象),返回调用register方法将其注册到分组中,然后在分组中处理调用了DeferredImportSelectorGroupingHandler#processGroupImports方法

在这里插入图片描述

processGroupImports 调用分组的DeferredImportSelectorGrouping#getImports方法,这里返回的是DeferredImportSelector.Group.Entry(封装了配置类),这里当前处理的是AutoConfigurationImportSelector,所以获取的AutoConfigurationImportSelector.AutoConfigurationGroup.Entry,调用this.group.process方法就是调用AutoConfigurationImportSelector.AutoConfigurationGroup#process方法

在这里插入图片描述

在这里插入图片描述

进入到AutoConfigurationImportSelector.AutoConfigurationGroup#process方法,又调用getAutoConfigurationEntry方法,返回AutoConfigurationImportSelector.AutoConfigurationEntry对象

在这里插入图片描述

getAutoConfigurationEntry方法首先调用getCandidateConfigurations方法,从项目或者所有依赖的jar的资源路径下META-INFO/spring.factories文件中获取所有的自动配置类(即xxxAutoConfiguration),这里找到了130个

  1. spring-boot-devtools.jar 3个
  2. spring-boot-autoconfigure.jar 127个

在这里插入图片描述

在这里插入图片描述

加粗样式

上面相当于是把常用的配置类都获取到了,接下来去重,去除排除的配置类(根据@SpringBootApplication的exclude和excludeName属性值),再根据AutoConfigurationImportFilter过滤器进行过滤,最后剩下27个满足条件的配置类,封装成AutoConfigurationImportSelector.AutoConfigurationEntry对象

在这里插入图片描述

回到AutoConfigurationImportSelector.AutoConfigurationGroup#process方法,将AutoConfigurationImportSelector.AutoConfigurationEntry添加到autoConfigurationEntries集合属性中

在这里插入图片描述

回到DeferredImportSelectorGrouping#getImports方法,再调用selectImports方法,根据autoConfigurationEntries集合,遍历创建Entry对象,返回List集合,====

在这里插入图片描述

在这里插入图片描述

最后回到调用getImports方法的地方,循环遍历Entry, 调用processImports方法,对上面的27个配置类,进行解析。这里可以看出processImports方法才是核心

在这里插入图片描述

最后paser执行完,从ConfigurationClassParserconfigurationClasses集合中取出所有解析过的配置类,通过BeanDefinition读取器加载到Spring容器中

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

至此算是完成了Springboot的自动配置,将相关的组件加载到Spring容器中!!!

总结

以上只是对SpringBoot自动配置的大致说明,如果有错误之处,欢迎评论指正!!!

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值