@SpringBootApplication注解是怎么生效的?
作者:程序员马丁
在线博客:https://open8gu.com
大话面试,技术同学面试必备的八股文小册,以精彩回答应对深度问题,助力你在面试中拿个offer。
回答话术
@SpringBootApplication
注解是一个组合注解,它包含三个元注解:
- @SpringBootConfiguration:本质上是一个
@Configuration
,它表示启动类也是一个配置类,我们可以在启动类中基于带有@Bean
注解的工厂方法手动装配一些组件。 - @ComponentScan:指定要扫描哪些包路径,从而将其中的类纳入或排除 Spring 管理,它用于实现基于路径半自动装配。
- @EnableAutoConfiguration:最核心的作用是通过
@Import
注解引入两个用于实现自动配置功能的核心组件,表示启用 SpringBoot 的自动装配机制。
其中,@EnableAutoConfiguration
注解对于启动自动装配功能尤其重要,它直接通过 @Import
注解引入了自动配置选择器 AutoConfigurationImportSelector
,又通过 @AutoConfigurationPackage
注解间接引入了基础包自动配置注册器:
AutoConfigurationImportSelector
:本质上是一个ImportSelector
,用于扫描META-INF/spring.factories
路径下的配置文件并加载其中指定的配置类。AutoConfigurationPackages.Registrar
:本质上是一个ImportBeanDefinitionRegistrar
,用于在项目启动时扫描启动类所在包的所有路径,并加载所需的配置类。
问题详解
1. @SpringBootApplication 的组成
当我们谈到“核心注解”时,恐怕没有什么注解会比启动类上的 @SpringBootApplication
更核心了。
它是一个组合注解,其包含的元注解如下:
- @SpringBootConfiguration:本质上是一个
@Configuration
,它表示启动类也是一个配置类,我们可以在启动类中基于带有@Bean
注解的工厂方法手动装配一些组件。 - @ComponentScan:指定要扫描哪些包路径,从而将其中的类纳入或排除 Spring 管理,它用于实现基于路径半自动装配。
- @EnableAutoConfiguration:最核心的作用是通过
@Import
注解引入两个用于实现自动配置功能的核心组件,表示启用 SpringBoot 的自动装配机制。
下面是这它们的源码,我们重点关注它们的“继承”结构:
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {
@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class)
})
public @interface SpringBootApplication {}
// SpringBootConfiguration
@Configuration
public @interface SpringBootConfiguration {}
// EnableAutoConfiguration
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration { }
@Import(AutoConfigurationPackages.Registrar.class)
public @interface AutoConfigurationPackage { }
搞懂了它的原理,我们就可以知道,我们不必总是使用 @SpringBootApplication
,按需使用也是完全可行的。
比如,按大多数项目的写法,我们其实只需要在启动类启用自动装配即可:
@EnableAutoConfiguration
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
- 关于 Spring 的组合注解机制,请参见:✅ Spring 的组合注解是什么?
- 关于
@ComponeScan
、@Import
与@Ccnfiguration
几个注解,请参见:✅ Spring 有哪些常用注解?
2. AutoConfigurationImportSelector
这个组件直译叫做自动配置导入选择器,它是通过 @EnableAutoConfiguration
注解上的 @Import(AutoConfigurationImportSelector.class)
引入的。它本质上是一个 ImportSelector
,作用是在应用启动的过程中,向 Spring 注册额外的配置类。
注意,在更早或更晚的 SpringBoot 版本中,这里引入可能是
ImportAutoConfigurationImportSelector
或者EnableAutoConfigurationImportSelector
,不过它们都是AutoConfigurationImportSelector
的子类,所以从功能上来说都是一样的。
这里说的“额外的配置类”,实际上就是 META-INF/spring.factories
路径下的配置文件。
其中,SpringBoot 默认的 spring-boot-autoconfigure
模块与 spring-boot
模块则提供了九成以上基本组件的配置类,而当我们引入额外的 starter 的时候,SpringBoot 会自动将 starter 下的配置类也一起加载进来。这就是自动装配的原理。
关于自动装配,更具体的内容请参见:✅ 什么是自动装配?
3. AutoConfigurationPackages.Registrar
这个组件本质上是一个 ImportBeanDefinitionRegistrar
,在项目启动时,它将扫描在 @AutoConfigurationPackage
注解中指定的包路径,然后将将路径下的配置类 —— 也就是带有 @Configuration
注解的类 —— 注册到 Spring 容器。
不过,如果你在 @AutoConfigurationPackage
并未指定包路径,那么它将直接把 @AutoConfigurationPackage
注解的 AnnotatedElement
的包路径全部都扫描一遍。
而由于 @SpringBootApplication 默认并没有覆写 @AutoConfigurationPackage 的扫描路径,这个属性总是空的,所以实际上 SpringBoot 总是会扫描启动类所在包的全部下级路径。
这就是 SpringBoot 的启动类要放包的最外层根本原因。
- 关于
@Import
注解与ImportBeanDefinitionRegistrar
的作用,请参见:@Import 注解是怎么生效的?- 关于自动装配,更具体的内容请参见:✅ 什么是自动装配?