【SpringBoot】SpringBoot源码解析第一章 SpringBoot的构造方法-CSDN博客
【SpringBoot】SpringBoot源码解析第二章 SpringBoot的run方法-CSDN博客
【SpringBoot】SpringBoot源码解析第三章 SpringBoot的自动化配置-CSDN博客
【SpringBoot】SpringBoot源码解析第四章 SpringBoot的bean接口-CSDN博客
【SpringBoot】SpringBoot源码解析第五章 SpringBoot的beanDefinition收集过程-CSDN博客
【SpringBoot】SpringBoot源码解析第六章 SpringBoot的getBean方法-CSDN博客
【SpringBoot】SpringBoot源码解析第七章 SpringBoot的感悟-CSDN博客
上一章我们分析了SpringBoot对象的run方法,这一章我们来分析SpringBoot自动配置的实现原理
参考源码:<spring.boot.version>2.3.12.RELEASE</spring.boot.version>
目录
2.2 没调用selectImports方法又是怎么实现自动配置的
SpringBoot的设计理念之一是约定大于配置,其中约定指的是默认配置。在SpringBoot框架中使用默认配置即可快速搭建一个应用,这些默认配置如何自动生效就是本篇讨论的主题
1、SpringBoot自动配置的实现原理
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
SpringBoot的自动配置是通过@SpringBootApplication注解来实现的,点击进入@SpringBootApplication注解
@SpringBootApplication内又嵌套了很多其他注解,其中和自动配置相关的是@EnableAutoConfiguration,点击进入
@EnableAutoConfiguration使用@import注解往Spring容器内添加了一个AutoConfigurationImportSelector类,该类的selectImports方法会获取自动配置类的信息,点击进入
跟着selectImports方法走到loadSpringFactories方法
调用链:
-> selectImports
-> getAutoConfigurationEntry(annotationMetadata)
-> getCandidateConfigurations(annotationMetadata, attributes)
-> SpringFactoriesLoader.loadFactoryNames
-> loadSpringFactories(classLoader)
loadSpringFactories方法会加载classpath目录下所有的META-INF/spring.factories文件,从文件中获取符合类型要求的类的全限定类名,这个方法我们在第一章SpringBoot对象的构造方法中就已经介绍过了
【SpringBoot】SpringBoot源码解析第一章 SpringBoot的构造方法-CSDN博客
到这里我们基本可以理清SpringBoot自动配置的原理:加载classpath目录下所有的META-INF/spring.factories文件,并且将其中符合自动化配置类要求的配置项通过java反射进行实例化,然后汇总并加载到Spring的容器
2、自动配置入口
如果在AutoConfigurationImportSelector的selectImports方法上debugger,会发现启动应用后不会走到这个方法,那么什么时候才会调用selectImports方法呢?如果没有调用selectImports方法,SpringBoot又是怎么实现自动配置的?我们逐个来解答
2.1 什么时候调用selectImports方法
AutoConfigurationImportSelector实现了DeferredImportSelector接口,DeferredImportSelector接口继承了ImportSelector接口,selectImports方法其实来自ImportSelector接口
应用启动到调用selectImports方法的过程如下
调用链:
-> ConfigurationClassParser.parse
-> this.parse(((AnnotatedBeanDefinition)bd).getMetadata(), holder.getBeanName());
-> processConfigurationClass
-> doProcessConfigurationClass(configClass, sourceClass, filter)
-> processImports
-> selectImports
processImports方法处理@import注解时,如果选择器实现了DeferredImportSelector接口,就会调用延迟选择器的handle方法,将选择器包装成holder放到延迟选择器内,否则直接调用选择器的selectImports方法
也就是说因为AutoConfigurationImportSelector实现了DeferredImportSelector接口,所以启动应用是不会调用AutoConfigurationImportSelector的selectImports方法的,AutoConfigurationImportSelector的selectImports方法并没有触发的时机
2.2 没有调用selectImports方法,SpringBoot又是怎么实现自动配置的
根据2.1的分析我们可以得知AutoConfigurationImportSelector实现了DeferredImportSelector接口,会走延迟选择器的handle方法这个分支。后续会走到延迟选择器的process方法
AutoConfigurationImportSelector的process方法会调用getAutoConfigurationEntry方法,这个方法就是1中介绍的获取自动配置全限定名的方法,即使不走AutoConfigurationImportSelector的selectImports方法,也可以拿到自动配置的信息,接着调用AutoConfigurationGroup类的selectImports方法,AutoConfigurationGroup是AutoConfigurationImportSelector的一个内部类,两个类都有selectImports方法,但它们并不相同,需要区分开来
3、总结
SpringBoot应用启动后会扫描classpath目录下所有的META-INF/spring.factories文件,从文件中获取自动化配置的类并实例化
下一章我们分析Spring和bean相关的接口