
一. 前言
说到SpringBoot,在面试中总绕不开对SpringBoot核心注解@SpringBootApplication的理解。这不,文哥班里的学生毕业了,在面试过程中,很多学员又被问到对这个注解的理解。文哥觉得,我们在回答这个问题的时候,不能只是泛泛而谈,或者只是背背面试题上的八股文。如果想让面试官记忆深刻,我们还得回答一些让面试官觉得不一样的东西。好了,废话不多说,我们直接来对这个注解进行深入剖析。
二. @SpringBootApplication注解剖析
2.1 SpringBoot自动配置--包扫描原理
首先我们看看@SpringBootApplication注解定义的位置,发现是在SpringBoot工程中的启动类上面:

那这个注解有哪些值得我们深挖的地方呢?我们按住ctrl键不放,然后左键点击进入到这个注解的内部:

2.2 @SpringBootConfiguration注解
在上图中的3个注解里,我们首先了解一下@SpringBootConfiguration注解。这个注解点击进去,我们发现它描述的就是当前注解修饰的类是配置类:

也就是说,有了该注解之后,我们的SpringBoot启动类就是一个配置类了。
2.3 @ComponentScan注解
我们再来看看@ComponentScan注解,这个注解我们在Spring课程里学习过,表示用来开启自动包扫描功能,所以在这里我就不做过多解释了。
2.4 @EnableAutoConfiguration注解
最后我们再来看看@EnableAutoConfiguration注解,点击进去,如下图所示:

我们发现,@EnableAutoConfiguration注解又包含两个字注解,分别是@AutoConfiguratonPackage注解和@Import注解。
2.5 @AutoConfiguratonPackage注解
我们先看@AutoConfiguratonPackage注解,点击进去,如下图所示:

2.6 Registrar类分析
我们继续点击,进入到这个类里面:

这个方法就是利用Registrar给容器中导入一系列组件,那该类到底是怎么注册的呢?我们可以打一个断点:

通过打断点发现:它的功能,就是把这个注解所在包下面的所有组件都导入到容器中!
2.7 包扫描分析
那包名到底是什么呢?我们可以查看一下:

通过断点,我们发现结果如下:

这就解释了我们之前在搭建SpringBoot工程的时候,要求所有组件必须定义在启动类的包下面了,只有这样才能被扫描的到!!!
三. SpringBoot源码分析--初始加载配置类
@SpringBootApplication注解,这个注解点击进去,我们发现@EnableAutoConfiguration注解,我们上一节讨论了@AutoConfigurationPackage注解,接下来我们讨论@Import({AutoConfigurationImportSelector.class})注解。

3.1 AutoConfigurationImportSelector类分析
我们点击进入AutoConfigurationImportSelector这个类,里面有一个方法selectImports,就是给给容器批量导入一些组件的方法。

selectImports方法内部的getAutoConfigurationEntry方法才是真正执行导入组件的操作。

getAutoConfigurationEntry方法里面的getCandidateConfigurations方法导入候选配置信息,我们可以打断点来看看,到底加载了哪些候选配置信息。

问题来了,这124项候选配置信息到底从何而来?
3.2 getCandidateConfigurations方法分析
我们继续进入getCandidateConfigurations方法内部。

然后进入loadFactoryNames方法内部:

接着继续进入loadSpringFactories方法内部:

3.3 spring.facories文件分析
到现在我们明白了,这124项候选配置信息的加载是从spring.facories文件中加载的,那么这个spring.factories文件在哪里???

我们打开spring.factories文件,其内容如下:

......

从22开始,一直到145行,我们发现不多不少,刚刚是124(145-22+1)项配置信息。
SpringBoot把这124项候选配置信息全部导入到容器里了吗?其实并不是。接下来我们分析SpringBoot的自动配置流程。
四. SpringBoot源码分析--自动配置类配置流程
SpringBoot批量导入的配置信息并没有全部生效,但自动配置类信息生效,必须要满足对应的条件注入,接下来我们就分析几个自动配置类。
4.1 AopAutoConfiguration分析

在加载候选配置信息的时候,配置类也是加载了的。

4.2 AopAutoConfiguration配置类的生效条件
我们打开AopAutoConfiguration配置类会发现,AopAutoConfiguration配置类要想生效,需要满足很多条件。

所以这个配置类是在IOC容器里面生效了的,我们可以验证一下:
@SpringBootApplication
public class App {
public static void main(String[] args) {
//获得ioc容器
ConfigurableApplicationContext context = SpringApplication.run(App.class, args);
//根据bean的类型,获取容器中bean的名称
String[] beanNamesForType = context.getBeanNamesForType(AopAutoConfiguration.class);
System.out.println(beanNamesForType.length);// 值为1 说明这个bean已经在ioc容器中存在。
}
}4.3 验证AspectJAutoProxyingConfiguration配置类
我们进入这个配置类继续观察,发现这个配置类的内部也在注入一些组件:

但是我们搜索发现,容器中并不存在org.aspectj.weaver.Advice这个bean!!!说明AspectJAutoProxyingConfiguration这个bean并没有注入到容器中。
4.4 验证缓存相关的配置类
我们先来看看缓存相关的自动配置。

CacheAutoConfiguration有没有导入到IOC容器,其实在加载候选配置信息的时候,已经导入了的。

我们打开这个配置类:

我们发现,CacheAutoConfiguration配置类需要生效,同样需要满足很多条件。
@Configuration(proxyBeanMethods = false) 标识当前类是一个配置类;
@ConditionalOnClass({CacheManager.class}) 条件注入,意思是当前配置类生效,类路径下必须存在CacheManager这个类,容器中存在吗?我们可以搜索一下:

@ConditionalOnBean({CacheAspectSupport.class}) 条件注入,意思是当前配置类生效,容器中必须存在CacheAspectSupport这个bean。我们可以测试一下容器中是否存在这个bean。
@SpringBootApplication
public class App {
public static void main(String[] args) {
//获得ioc容器
ConfigurableApplicationContext context = SpringApplication.run(App.class, args);
//根据bean的类型,获取容器中bean的名称
String[] beanNamesForType = context.getBeanNamesForType(CacheAspectSupport.class);
System.out.println(beanNamesForType.length); // 0
}
} 我们发现容器中并没有这个bean的名称,说明这个bean在容器中压根没有。
其实看到这里,我们就不用往下看了,因为CacheAspectSupport这个bean在IOC容器中不存在,所以当前的配置类CacheAutoConfiguration也不会生效。
@SpringBootApplication
public class App {
public static void main(String[] args) {
//获得ioc容器
ConfigurableApplicationContext context = SpringApplication.run(App.class, args);
//根据bean的类型,获取容器中bean的名称
String[] beanNamesForType = context.getBeanNamesForType(CacheAutoConfiguration.class);
System.out.println(beanNamesForType.length); //为0,说明没有在ioc容器中生效
}
}五. 总结
关于核心注解@SpringBootApplication的解析,文哥带大家从源码的角度,深入解析了这个注解。希望大家在面试的时候,可以根据文哥的描述,深入地给面试官去剖析SpringBoot的自动配置。如果各位可以做到这样,文哥相信你一定能够在众多面试候选者中脱颖而出。
关注公众号了解更多前沿技术!

点击【阅读原文】,零基础免费学Java!
原文作者:Java架构栈;如有侵权,请联系管理员删除。