我们知道SpringBoot中底层帮我们做了很多事情,但是只会用是远远不够的,我们还需要对它的内部实现原理进行一定的了解,知其然并且知其所以然,才能在工作和学习中游刃有余
本文是笔者通过阅读源码和看视频所总结出来的,将从最初的主启动类开始分析,如有差错,欢迎文明讨论
笔者所使用SpringBoot版本为2.5.3,版本不同,源码可能会有细节上的不同
我们在创建一个SpringBoot项目时,IDEA会自动生成一个SpringBoot的启动类。如下图:
而这其中的注解@SpringBootApplication
也是原理所在,它是一个组合注解,点进去如下图:
除了常规注解之外,我们发现它还被@SpringBootConfiguration
,@EnableAutoConfiguration
,@ComponentScan
三个注解标注,这也是接下来需要重点了解的三个注解
我们将重头戏放到后面,先分析不那么复杂的注解
- 首先刨析
@ComponentScan
,以下是@Component的源码解释
翻译过来:将@Configuration
注解标注的类配置组件扫描指令,提供和Spring的XML文件中<context:component-scan>
平行的支持(即意义等同于它)
说人话就是表示自动扫描主启动类同包和子包下的组件和bean,并将其加载到SpringIOC容器中。
- 接下来再看
@SpringBootConfiguration
注解,点进去如下图:
将上面的英文注解翻译过来,大概意思就是它是一个SpringBoot配置类,应用程序应该只包含一个@SpringBootConfiguration
,大多数惯用的SpringBoot应用程序将从@SpringBootApplication
继承它
说白了就一句话,这是一个SpringBoot的配置类
他被@Configuration
标注,进入它:
我们发现它被@Component
注解标注,因此从这里我们可以知道一个SpringBoot应用程序本质上还是一个Spring组件
- 最后也是最重要的一个注解
@EnableAutoConfiguration
,它是自动配置的核心注解,点进该注解:
这个注解表示开启自动配置,它主要被@AutoConfigurationPackage
和@Import(AutoConfigurationImportSelector.class)
两个注解标注,首先分析@AutoConfigurationPackage
,进入该注解
该注解用来自动注册包,可以看到其中有一个@Import
注解导入了一个AutoConfigurationPackages.Registrar.class
,它用来注册包,这里和前面我们说的扫描包是连起来的,扫描过的包在这里注册!
返回到上一级, 我们分析另一个@Import(AutoConfigurationImportSelector.class)
它导入了一个类AutoConfigurationImportSelector,这个类是自动配置的核心类,进入该类的主要方法:
getAutoConfigurationEntry()
该方法用来获取自动配置属性,其中调用了一个同级方法如下:
getCandidateConfigurations()
用来获取并返回候选配置,可以看到候选配置的获取是通过调用SpringFactoriesLoader
类的一个静态方法loadFactoryNames()
实现的,并且传入了一个方法getSpringFactoriesLoaderFactoryClass(),它用来获取加载配置类的工厂类,进入该方法:
可以看到返回的是@EnableAutoConfiguration
注解标注的类!想想我们刚才走过来的路,这个被标注的类不就是启动类?所以说绕了一大圈我们发现,最终其实是让SpringBoot的主启动类来加载我们的所有候选配置类
返回到刚才的loadFactoryNames
方法,进入它:
我们发现,loadFactoryNames()
会返回一个List集合,存放了需要加载的自动配置类的全限定名,Spring会根据这些全限定名来讲对应的配置类注册到IOC容器中,它调用了同级的loadSpringFactories
方法,通过传入的类加载器(这个类加载器实际上也就是SpringBoot的启动类加载器)来加载了一个常量路径FACTORIES_RESOURCE_LOCATION
,点进去:
发现该路径指向META-INF/spring.factories
,它表示加载所有jar包中META-INFO下的spring.factories文件,而spring-boot-autoconfigure.jar包下存在该路径和该文件,并将他们封装成了Properties类型文件。
也就是说,SpringBoot启动时将会加载所有META-INF下的spring.factories的自动配置类,但到这里并没有结束。
进入该文件我们会发现他们都是以XXXAutoConfiguration来结尾的,表明他们是自动配置类,我们以HttpEncodingAutoConfiguration
为例,点进去,会发现该类被注解@EnableConfigurationProperties
标注
一旦自动配置类生效,这个注解表示会将该XXXProperties类和一个配置文件相绑定,也就是说该Properties类中的属性会和配置文件中的一一对应,我们可以通过配置文件设置Properties类中对应属性的值,注意名字不能写错。
而自动配置类生效也是需要条件的,我们可以看到上面例子中的配置类被一些@ConditionalOnXXX
注解标注,这类注解叫做条件注解,如@ConditionalOnWebApplication
表示当前要为web环境等等,只有这些条件注解的条件都满足了,这个自动配置类才能真正生效!
走到这里,SpringBoot的自动装配过程才算完成
下面是一些常用条件注解的作用:
@ConditionalOnJava:系统Java版本是否符合要求
@ConditionalOnBean:容器存在指定Bean
@ConditionalOnMissingBean:容器中不存在指定Bean
@ConditionalOnClass:类路径中存在指定class
@ConditionalOnMissingClass:类路径中不存在指定class
@ConditionalOnExpression:满足SpEL表达式指定
@ConditionalOnSingleCandidate:容器中只有一个指定的Bean,或者这个Bean是首选Bean
@ConditionalOnProperty:检查指定属性是否有指定值
@ConditionalOnResource:类路径下是否存在指定资源
@ConditionalOnWebApplication:当前应用是一个web应用环境
@ConditionalOnNotWebApplication:当前应用不是一个web应用环境
@ConditionalOnJndi:JNDI存在指定项
以上内容均是笔者通过阅读源码以及看视频资料所总结出来的,一些地方可能还不够细致,如有错误,欢迎文明讨论