跳到主要内容 Spring Boot 自动配置原理 | 极客日志
Java java
Spring Boot 自动配置原理 Spring Boot 自动配置机制允许容器启动时自动将依赖包中的配置类和 Bean 注册到 IoC 容器中。其核心在于@SpringBootApplication 注解中的@EnableAutoConfiguration,通过 ImportSelector 读取 META-INF/spring.factories 或 AutoConfiguration.imports 文件获取候选配置类,并结合@Conditional 系列注解进行条件判断,动态加载所需组件,从而减少手动配置工作。
CryptoLab 发布于 2026/3/28 0 浏览什么是自动配置?
Spring Boot 的自动配置 :当 Spring 容器启动后,一些配置类、bean 对象 等就自动存入 IoC 容器 中,而不再需要我们手动去声明,从而简化了程序开发过程,省去了繁琐的配置操作。
也就是说,Spring Boot 的自动配置,就是 Spring Boot 将依赖 jar 包 中的配置类 以及 Bean 加载到 Spring IoC 容器中的过程。
在本篇文章中,我们主要学习一下两个方面:
Spring 如何将对象加载到 Spring IoC 容器中
Spring Boot 是如何进行实现的
我们首先来看 Spring 是如何加载 Bean 的。
Spring 加载 Bean
当我们在项目中引入第三方的包时,其实就是在该项目下引入第三方的代码,我们通过在该项目下创建不同的目录来模拟第三方代码的引入:
当前项目目录为 com.example.springautoconfig ,模拟第三方代码文件在 com.example.autoconfig 目录下。
第三方文件代码:
@Component
public class AutoConfig {
public void test () {
System.out.println("test..." );
}
}
获取 AutoConfig:
@SpringBootTest
class SpringAutoconfigApplicationTests {
@Autowired
private ApplicationContext context;
@Test
void contextLoads () {
AutoConfig bean = context.getBean(AutoConfig.class);
System.out.println(bean);
}
}
运行结果:
微信扫一扫,关注极客日志 微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
相关免费在线工具 Keycode 信息 查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online
Escape 与 Native 编解码 JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online
JavaScript / HTML 格式化 使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online
JavaScript 压缩与混淆 Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online
Base64 字符串编码/解码 将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
Base64 文件转换器 将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
此时显示没有 com.example.autoconfig.AutoConfig 这个类型的 bean。
Spring 使用 类注解(@Controller、@Service、@Repository、@Component、@Configuration)和 @Bean 注解 帮助我们将 Bean 加载到 Spring IoC 容器中时,有一个前提:这些注解需要和 Spring Boot 启动类(@SpringBootApplication 标注的类)在同一个目录下 。
而在上述项目中,启动类所在目录为 com.example.springautoconfig,而 AutoConfig 类位于 com.example.autoconfig 目录下,因此,Spring Boot 并没有扫描到。
可是,当我们引入第三方的 jar 包时,第三方的 jar 代码目录也不在启动类的目录下,那么,如何让 Spring 帮我们管理这些 Bean 的呢?
我们可以通过指定路径或引入的文件 告诉 Spring,让 Spring 进行扫描。
@ComponentScan 组件扫描
@Import 导入
@ComponentScan 使用 @ComponentScan 注解,指定 Spring 扫描路径:
@SpringBootApplication
@ComponentScan("com.example.autoconfig")
public class SpringAutoconfigApplication {
public static void main (String[] args) {
SpringApplication.run(SpringAutoconfigApplication.class, args);
}
}
那么,Spring Boot 是否使用了这种方式呢?
显然没有。若 Spring Boot 采用这种方式,当我们引入大量的第三方依赖,如 MyBatis、jackson 等时,就需要在启动类上配置不同依赖需要扫描的包,非常繁琐。
@Import
导入类
导入 ImportSelector 接口的实现类
导入类 @Import(AutoConfig.class)
@SpringBootApplication
public class SpringAutoconfigApplication {
public static void main (String[] args) {
SpringApplication.run(SpringAutoconfigApplication.class, args);
}
}
@Component
public class AutoConfig2 {
public void test () {
System.out.println("test..." );
}
}
@Import({AutoConfig.class, AutoConfig2.class})
@SpringBootApplication
public class SpringAutoconfigApplication {
public static void main (String[] args) {
SpringApplication.run(SpringAutoconfigApplication.class, args);
}
}
显而易见,这种方式也比较繁琐,因此,Spring Boot 也没有采用。
导入 ImportSelector 接口的实现类 public class MyImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String []{"com.example.autoconfig.AutoConfig" , "com.example.autoconfig.AutoConfig2" };
}
}
@Import(MyImportSelector.class)
@SpringBootApplication
public class SpringAutoconfigApplication {
public static void main (String[] args) {
SpringApplication.run(SpringAutoconfigApplication.class, args);
}
}
但是,它们都有一个明显的问题:使用者需要知道第三方依赖中有哪些 Bean 对象或配置类 ,若我们在导入过程中漏掉了一些 Bean,就可能会导致我们的项目出现问题。
依赖中有哪些 Bean,使用时需要配置哪些 Bean,这些问题第三方依赖最为清楚,那么,能否由第三方依赖来做这些事情呢?
比较常见的方法是第三方依赖提供一个注解 ,而这个注解一般是以 @EnableXxx 开头的注解,而注解中封装的就是 @Import 注解。
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Import(MyImportSelector.class)
public @interface EnableAutoConfig { }
@EnableAutoConfig
@SpringBootApplication
public class SpringAutoconfigApplication {
public static void main (String[] args) {
SpringApplication.run(SpringAutoconfigApplication.class, args);
}
}
可以看到,这种方式也可以导入第三方依赖提供的 Bean,且这种方式不需要使用方知道第三方依赖中有哪些 Bean 对象或配置类 ,而在 Spring Boot 中也是使用的这种方式。
SpringBoot 原理分析 Spring Boot 是如何进行实现的?让我们从 Spring Boot 的启动类开始看:
由@SpringBootApplication 标注的类就是 Spring Boot 项目的启动类:
这个类与普通类的唯一区别就是 @SpringBootApplication 注解,这个注解也是 Spring Boot 实现自动配置的核心。
@SpringBootApplication 是一个组合注解,注解中包含了:
JDK 中提供了 4 个 标准的用来对注解类型进行注解 的注解类,称之为 meta-annotation(元注解) 。
@Retention :描述注解保留的时间范围
@Target :描述注解的使用范围
@Documented :描述在使用 javadoc 工具为类生成帮助文档时是否保留其注解信息
@Inherited :使被其修饰的注解具有继承性(若某个类使用了 @Inherited,则其子类将自动具有该注解)
2. @SpringBootConfiguration:
标识当前类是一个配置类,里面其实就是@Configuration,只是做了进一步的封装。
其中,@Indexed 注解是用来加速应用启动的。
3. @EnableAutoConfiguration(开启自动配置)
是 Spring 自动配置的核心注解,我们在后续详细理解。
可以通过 basePackageClasses 或 basePackages 来定义要扫描的特定包,若没有定义特定的包,将从声明该注解的类的包开始扫描 ,这也是 Spring Boot 项目声明的注解类为什么必须在启动类目录下。
接下来,我们重点来看 @EnableAutoConfiguration(开启自动配置) 。
@EnableAutoConfiguration @EnableAutoConfiguration 中主要包含两部分:
@Import(AutoConfigurationImportSelector.class)
@AutoConfigurationPackage
我们先来看 @Import(AutoConfigurationImportSelector.class)。
@Import(AutoConfigurationImportSelector.class) 使用 @Import 注解,导入了实现 ImportSelector 接口的实现类:
在 selectImports() 方法中,调用了 getAutoConfigurationEntry() 方法,获取可自动配置的配置类信息。
我们继续看 getAutoConfigurationEntry() 方法:
在 getAutoConfigurationEntry() 方法中,主要通过 getCandidateConfigurations(annotationMetadata, attributes) 方法 和 fireAutoConfigurationImportEvents(configurations, exclusions) 方法,获取在配置文件中配置的所有自动配置类的集合 。
我们先看 getCandidateConfigurations(annotationMetadata, attributes) 方法:
在 getCandidateConfigurations(annotationMetadata, attributes) 方法中,使用 ImportCandidates 进行加载。
从断言 的错误信息中我们可以找到答案:META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 。
也就是说,getCandidateConfigurations 方法会获取所有基于 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 文件中配置类的集合。
META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 文件:
查看 RedisAutoConfiguration :
可以看到,在使用 redis 时常用的 RedisTemplate 和 StringRedisTemplate 就位于其中,在我们需要使用时直接使用 @Autowired 进行注入就可以了。
但是,由于当前项目并没有引入 redis 相关 jar 包,此时这个类并不能被加载。
也就是说在加载自动配置类 的时候,并不是将所有的配置全部加载进来 ,而是会先进行判断 ,根据 @ConditionalOnMissingBean 、@ConditionalOnSingleCandidate 等注解的判断进行动态加载 。
即,在配置文件 中使用 @Bean 声明对象,spring 会自动调用配置类中使用 @Bean 标识的方法,并将对象存放到 Spring IoC 中,但是,在加载自动配置类的时候,并不是将所有的配置全部加载进来,而是会通过 @Conditional 等注解的判断进行动态加载 (@Conditional 是 spring 底层注解,会根据不同的条件,进行条件判断,若满足指定条件,配置类中的配置才会生效)。
我们继续看 fireAutoConfigurationImportEvents 方法,找到是从哪里获取配置类的:
可以看到,fireAutoConfigurationImportEvents 方法最终会从 META-INF/spring.factories 中获取配置类的集合。
我们来看 META-INF/spring.factories :
META-INF/spring.factories 文件是 Spring 内部提供的一个约定俗称的加载方式 ,只需要在模块的 META-INF/spring.factories 文件中进行配置 ,Spring 就会把相应的实现类注入到 Spring 容器中。
例如,有一个自动配置类,希望 Spring Boot 在启动时自动加载这个配置,我们就可以在 META-INF/spring.factories 文件按照指定格式进行配置,让 Spring Boot 应用启动时,读取这个 spring.factories 文件,根据文件中指定的配置类来进行自动配置。
spring 会加载所有 jar 包下的 META-INF/spring.factories 文件 。
META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 和 META-INF/spring.factories 都在引入的起步依赖中:
我们继续看 AutoConfigurationPackage 。
AutoConfigurationPackage 在这个注解中,主要导入了一个配置文件 AutoConfigurationPackages.Registrar.class 。
Registrar 实现了 ImportBeanDefinitionRegistrar 接口,可以被 @Import 导入到 spring 容器中。
new PackageImports(metadata).getPackageNames().toArray(new String[0]) :当前启动类所在的包名。
也就是说,@AutoConfigurationPackage 的作用是将启动类所在的包下面所有的组件都扫描注册到 spring 容器中 。
最后,我们来总结一下 Spring Boot 自动配置的流程 。
SpringBoot 自动配置流程 Spring Boot 的自动配置的入口是 @SpringBootApplication 注解,在这个注解中,主要封装了 3 个注解:
@SpringBootConfiguration:标识当前类是配置类
@ComponentScan(包扫描):可以通过 basePackageClasses 或 basePackages 定义要扫描的特定包,若没有定义特定的包,将从声明该注解的类的包开始扫描 ,也就是说,默认情况下扫描的是启动类所在的当前包以及子包 。
@EnableAutoConfiguration(开启自动配置):主要包含两部分:
@Import(AutoConfigurationImportSelector.class) :读取 META-INF/spring.factories 和 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 文件中定义的配置类
@AutoConfigurationPackage:将启动类所在的包下所有组件都注入到 Spring 容器中