本文基于SpringBoot 2.5.7版本进行讲解
前文回顾:在上一篇文章,SpringBoot自动配置之AutoConfigurationImportSelector - SpringBoot自动配置(二),讲到AutoConfigurationImportSelector的importSelector()方法通过调用getAutoConfigurationEntry()来获取需要自动配置的Bean信息。
但是,在第一篇文章,SpringBoot自动配置之@SpringBootApplication注解 - SpringBoot自动配置(一),我也讲到其实SpringBoot并没有通过AutoConfigurationImportSelector类的importSelector()方法来获取自动配置的Bean信息。
有些读者,可能也在AutoConfigurationImportSelector类的selectImports()方法断点了,结果发生debug的时候,程序根本就没有进入到这个方法。
看到这里,我们心中必定是十万个为什么?
AutoConfigurationImportSelector不是实现了ImportSelector接口吗?为什么selectImports()方法没有被调用?- 既然Spring Boot不通过
AutoConfigurationImportSelector的selectImports()方法来获取需要自动配置的Bean信息,那么从哪里获取? 
别急,这就是本文讲解的内容。让我们带着这个问题,一起看下去吧。
配置调试环境
既然,程序没有调用AutoConfigurationImportSelector类的selectImports()方法。那么,我们就自己创建一个简单的ImportSelector接口的实现类,然后看看SpringBoot会不会调用这个自定义的ImportSelector实现类。
需要被注入的Bean:Hello
1  | java复制代码public class Hello {  | 
自定义ImportSelector实现类:HelloImportSelector
1  | java复制代码public class HelloImportSelector implements ImportSelector {  | 
SpringBoot启动类:SpringTestApplication
1  | java复制代码@Import(HelloImportSelector.class)  | 
调试过程
到这里,就配置好了调试环境。接下来,我们在HelloImportSelector类的selectImports()方法打上断点,来看看程序会不会调用这个方法。
开始调试
看上图,我们知道SpringBoot程序是调用了selectImports()方法的。
追踪调用栈
既然,我们知道SpringBoot程序是会调用HelloImportSelector类的selectImports()方法,那么就好办了。
现在我们就沿着调用栈来一步一步追踪是哪里调用了这个selectImports()?
这里给出一部分调用栈的截图。我们看到,ConfigurationClassParser的processImports()方法调用了HelloImportSelector的selectImports方法。
那么接下来,我们就来看看这个processImports()方法做了什么吧。
ConfigurationClassParser类的processImports()方法
下面这里给出processImports()方法的定义和部分源码:
(我们不用去看这个方法的定义和部分源码,这里列出只是为了我后面解释的时候,读者能够翻来对照,读者可以直接跳过方法源码直接看文字部分。)
定义:
1  | java复制代码private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,  | 
部分源码:
1  | kotlin复制代码for (SourceClass candidate : importCandidates) {  | 
这里就是文字部分了:
我们再精确点,看看是processImports()方法的那一部分代码调用了selectImports()方法。
1  | java复制代码if (selector instanceof DeferredImportSelector) {  | 
看到这个if-else语句,相信大家都懂了。
AutoConfigurationImportSelector类的selectImports()方法没有被调用,而我们自定义的HelloImportSelector方法的selectImports()方法被调用的原因就是:AutoConfigurationImportSelector实现了DeferredImportSelector接口。
简单讲讲ConfigurationClassParser的processImports()方法
现在我们翻回去看看刚刚上面贴出的processImports()的部分源码。
看代码的if-else语句判断部分就可以了。
processImports()方法会遍历importCandidates变量,然后判断里面的元素是否是ImportSelector或ImportBeanDefinitionRegistrar的实现类,否则就是@Configuration类来处理。
我们也能猜到importCandidates变量就是@Import(xxx)里面的xxx类。
这就是为什么@Import注解能够接收ImportSelector和ImportBeanDefinitionRegistrar实现类、@Configuration配置类以及普通的Bean对象,支持四种不同类型的类并完成Bean注入的原因。
对@Import注解不了解的读者,可以看Spring的@Import注解四种使用方式进行了解。
SpringBoot怎么获取需要自动配置的Bean信息?
看过SpringBoot自动配置之AutoConfigurationImportSelector - SpringBoot自动配置(二)的知道,AutoConfigurationImportSelector实现了DeferredImportSelector接口,而DeferredImportSelector接口又实现了ImportSelector接口,所以AutoConfigurationImportSelector接口还是实现了selectImports()方法。
在selectImports()方法中,我们又讲到selectImports()方法其实是通过调用getAutoConfigurationEntry()方法来拿到需要自动配置的bean信息。
既然我们在selectImports()方法断点发现SpringBoot并没有调用这个方法。那么我们不妨大胆猜想一下,SpringBoot最终会不会是直接通过调用getAutoConfigurationEntry()方法来获取需要自动配置的bean信息。
那么接下来,我们来求证一下。
可以看到SpringBoot确实是调用了这个方法来获取需要自动配置的bean信息。
本文转载自: 掘金