ITPub博客

首页 > 数据库 > 数据库开发技术 > 超实用干货!SpringBoot核心注解@SpringBootApplication原理精讲

超实用干货!SpringBoot核心注解@SpringBootApplication原理精讲

原创 数据库开发技术 作者:Finally_m 时间:2022-09-23 08:03:00 0 删除 编辑
点击上方蓝字关注我们

一. 前言

说到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架构栈;如有侵权,请联系管理员删除。

请登录后发表评论 登录
全部评论

注册时间:2021-04-13

  • 博文量
    573
  • 访问量
    243903