SpringBoot系列之启动流程3-自动装配与@SpringBootApplication注解

Posted 孔令翰-技术博客

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SpringBoot系列之启动流程3-自动装配与@SpringBootApplication注解相关的知识,希望对你有一定的参考价值。

前言

前面两篇文章我们已经研究过SpringBootApplication类的构造方法和 run 方法,这篇文章会研究@SpringBootApplication注解。

正文

@SpringBootApplication注解基本在每一个 springboot 项目中都会看到,通常标注在启动类上。直接看源码:

image-20210606163232129

发现这是一个复合或者说组合注解,有三个子注解构成:

  • SpringBootConfiguration
  • EnableAutoConfiguration
  • ComponentScan

SpringBootConfiguration注解非常简单,他就是Springp非常常见的用来标识配置类的注解Configuration换了个名字。

ComponentScan注解也很常见,用来标识出 IOC 容器扫描 Bean 的范围。

我们把重点放在@EnableAutoConfiguration注解上,翻译过来就是“启动自动装配”,哎呦不得了,这是 SpringBoot 的卖点之一自动装配啊,值得我们深入研究。

@EnableXXX

SpringBoot 提倡"约定大于配置",@EnableXXX也体现了这一点。@EnableXXX是 SpringBoot 中的注解常用的一种命名规则,用来将一组 bean 装配进 Spring 容器,达到封装某些相关的 bean并一次性注入IOC 容器的效果,常用来启用某个可选的服务。常见的像@EnableAsync,@EnableAutoConfiguration

这些@EnableXXX注解都有一个共同点,点进注解源码就能发现他们都被@Import(XXX)注解修饰,所以@Import 注解才是我们的重点。

打开@Import 注解,查看注解上的 JavaDoc,大意是:

被@Configuration修饰的类或者ImportSelector接口的实现类或者ImportBeanDefinitionRegistrar接口的实现类,这三者可以使用Import 注解,来向 IOC 容器中批量注入一组 Bean。

为什么要提供三种方式呢,因为注解修饰的方式最简单直接,而通过实现接口的方式可以向实现类中传入更多容器环境上下文信息,更加定制化。

@EnableAutoConfiguration

接下来我们进入正题,探索SpringBoot 自动装配的总开关EnableAutoConfiguration注解。

image-20210602221157881

这个注解点开之后,发现正是由@Import修饰,我们去查看AutoConfigurationImportSelector这个类,这个类我们从名字猜测是ImportSelector 的实现类,点进去发现是DeferredImportSelector的实现类,不过DeferredImportSelector继承自ImportSelector,所以我猜测功能可能类似。下面我们开始打断点 Debug。

AutoConfigurationImportSelector#selectImports方法处打断点,启动容器发现竟然没走进来?!看来DeferredImportSelector接口有自己特殊的地方,我们在这个类里搜索selectImports,发现内部类里还有一个方法:AutoConfigurationImportSelector.AutoConfigurationGroup#selectImports,我在这个方法上打断点,这次走了进来:

image-20210602222449186

我们观察这个方法的发现,这个方法主要是对autoConfigurationEntries这个类属性进行操作,并最终返回了这个属性的包装结果,所以我们猜测autoConfigurationEntries属性是我们想通过自动装配注册进 IOC 容器里面的 Bean 集合。我们使用 IDE 查看这个属性的赋值所在,发现只有一处,就是在AutoConfigurationImportSelector.AutoConfigurationGroup#process方法里:

image-20210602222835461

我们沿着这个线索,继续向上查找代码,进入AutoConfigurationImportSelector#getAutoConfigurationEntry

image-20210602223110172

再向上查找,进入AutoConfigurationImportSelector#getCandidateConfigurations

image-20210602223848446

image-20210602224300691

看到这里已经接近“真相”了,最后调用了经典的SpringFactoriesLoader.loadFactoryNames方法来查找类(关于SpringFactoriesLoader.loadFactoryNames方法,在《SpringBoot系列之启动流程1-SpringApplication的构造方法》文章中有详细讲解,传送门),查找的 key 是EnableAutoConfiguration。我们打开 SpringBoot 自带的 spring.fatories文件:

image-20210606165511908

发现 SpringBoot 自己就提供了很多需要自动装配进 IOC 容器的类,有一百多个,那这些类都会被注册进 IOC 容器中么?其实不是的,这些只是蓝本,SpringBoot 还会根据环境中的配置、是否有哪些 bean、是否有哪些 class 文件等信息,进行下一步的条件装配(也就是@Conditional 条件装配,将单独写文章分析),最后将合适的Bean 注册进 IOC 容器中,完成自动装配。

总结

以上就是 SpringBoot 自动装配的初步分析,其中尚有细节没有研究,但总体的原理已经大致明白。

总结SpringBoot 的自动装配原理:根据classpath 下的所有 jar包中的 spring.fatories 工厂配置文件,查找key 为EnableAutoConfiguration的类作为蓝本,结合@Conditional 条件装配,将筛选后的类加入到 IOC 容器中,完成自动装配

以上是关于SpringBoot系列之启动流程3-自动装配与@SpringBootApplication注解的主要内容,如果未能解决你的问题,请参考以下文章

[Interview]Java 面试宝典系列之 Spring Boot

SpringBoot自动装配流程

SpringBoot——SpringBoot四大核心之自动装配(源码解析)

SpringBoot——SpringBoot四大核心之自动装配(源码解析)

EurekaServer自动装配及启动流程解析

SpringBoot自动配置/装配(SPI)