【SpringBoot】深入浅出 SpringBoot 自动装配
本文深入解析了SpringBoot自动装配机制的发展历程与实现原理。文章首先回顾了传统Spring框架的配置痛点,包括XML配置臃肿、注解配置零散等问题。随后重点剖析了SpringBoot2.x的自动装配机制,详细讲解了从@SpringBootApplication注解触发、AutoConfigurationImportSelector执行到条件筛选的完整流程,并解释了spring.factori
目录
3.1 核心入口:@SpringBootApplication 注解
3.2 核心执行类:AutoConfigurationImportSelector 源码解析
第二步:核心逻辑方法 getAutoConfigurationEntry
第三步:加载候选配置类 getCandidateConfigurations
3.3 配置加载:SpringFactoriesLoader 与 spring.factories
3.4 高频疑问:spring.factories 文件是每个 jar 包都有吗?
四、SpringBoot 2.x 自动装配的灵活性:自定义配置优先
五、关键变化:SpringBoot 3.x 中 spring.factories 的替代方案
在 Java 后端开发的历程中,Spring 框架的出现让面向对象编程与依赖注入思想深入人心,但早期的 Spring 配置方式却让开发者陷入了 “配置地狱”;而 SpringBoot 的横空出世,以 “约定大于配置” 的理念彻底改变了这一现状,其中自动装配更是核心中的核心。本文将从传统 Spring 的配置痛点出发,聚焦 SpringBoot 2.x 拆解自动装配的实现原理,补充 SpringBoot 3.x 的核心变化,带你完整理解这一 “黑科技” 背后的逻辑。
一、传统 Spring 的配置之 “痛”
在 SpringBoot 诞生之前,我们使用纯 Spring 框架开发项目时,想要让一个功能跑起来,需要编写大量的配置代码 / 文件,核心痛点集中在以下几个方面:
1.1 XML 配置的 “臃肿”
早期 Spring 以 XML 配置为主,哪怕是简单的数据源、事务管理器、Bean 注册,都需要在applicationContext.xml中逐一声明:
<!-- 配置数据源 -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/test"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</bean>
<!-- 配置JdbcTemplate -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 配置事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
一个简单的数据库操作,就需要十几行 XML 配置;如果是复杂项目,XML 文件动辄数百行,维护成本极高。
1.2 注解配置的 “零散”
后来 Spring 引入了注解配置(如@Configuration、@Bean),虽然摆脱了 XML,但仍需要开发者手动编写大量配置类:
@Configuration
public class DataSourceConfig {
// 手动配置数据源
@Bean
public DruidDataSource dataSource() {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/test");
dataSource.setUsername("root");
dataSource.setPassword("123456");
return dataSource;
}
// 手动配置JdbcTemplate
@Bean
public JdbcTemplate jdbcTemplate(DruidDataSource dataSource) {
return new JdbcTemplate(dataSource);
}
}
每个功能模块都需要对应一个配置类,开发者需要关注 “如何配置”,而非 “如何实现业务”,违背了 “关注点分离” 的原则。
1.3 依赖适配的 “繁琐”
不同框架(如 MyBatis、Redis、MQ)集成到 Spring 时,需要手动适配:比如集成 MyBatis,要手动配置SqlSessionFactory、MapperScannerConfigurer;集成 Redis,要手动配置RedisTemplate、JedisConnectionFactory。一旦依赖版本变化,配置代码还需要同步修改,极易出错。
二、SpringBoot 自动装配的 “魔力”
SpringBoot 的核心目标就是 “简化配置”,而自动装配(AutoConfiguration)正是实现这一目标的关键。使用 SpringBoot 后,上述所有配置都可以 “消失”—— 只需引入对应的 starter 依赖,SpringBoot 就能自动完成所有配置,开发者只需专注业务代码。
2.1 一个极简的 SpringBoot 2.x 示例
以数据库操作为例,SpringBoot 2.x 项目中只需两步:
1.引入 starter 依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
</dependency>
在application.yml中配置基础属性:
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/test
username: root
password: 123456
无需编写任何配置类,DataSource、JdbcTemplate等 Bean 会自动注册到 Spring 容器中,直接注入即可使用:
@Service
public class UserService {
@Autowired
private JdbcTemplate jdbcTemplate; // 直接使用,无需手动配置
// 业务代码...
}
这就是自动装配的魔力 ——SpringBoot 根据 “约定”(依赖、配置)自动完成 Bean 的注册和配置,让开发者从繁琐的配置中解放出来。
三、SpringBoot 2.x 自动装配的实现原理
自动装配并非 “玄学”,而是 SpringBoot 2.x 基于 Spring 原有机制的扩展,核心逻辑可拆解为 “触发入口→加载配置→条件筛选→Bean 注册” 四步。
3.1 核心入口:@SpringBootApplication 注解
@SpringBootApplication是自动装配的 “总开关”,它是一个组合注解,核心子注解是@EnableAutoConfiguration:

@EnableAutoConfiguration的底层通过@Import(AutoConfigurationImportSelector.class)导入核心类 —— 这是自动装配的 “执行入口”,所有自动配置的逻辑都从这个类开始。

3.2 核心执行类:AutoConfigurationImportSelector 源码解析
AutoConfigurationImportSelector实现了DeferredImportSelector接口(保证自动配置类加载优先级低于用户自定义配置),其核心方法是selectImports,我们逐行拆解你提供的这段核心代码:

第一步:核心入口方法 selectImports
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
// 1. 检查自动装配是否开启(可通过spring.boot.autoconfigure.enable=false关闭)
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS; // 返回空数组,不加载任何自动配置类
}
// 2. 核心逻辑:获取自动配置入口(加载、筛选配置类)
AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);
// 3. 将筛选后的配置类列表转为字符串数组返回
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
这段代码是自动装配的 “总调度”,真正的核心逻辑在getAutoConfigurationEntry方法中。

第二步:核心逻辑方法 getAutoConfigurationEntry
protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
// 前置校验:确认自动装配开启且当前环境合法
if (!isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
}
// 1. 获取@EnableAutoConfiguration注解的属性(如exclude、excludeName)
AnnotationAttributes attributes = getAttributes(annotationMetadata);
// 2. 加载所有候选的自动配置类(从spring.factories中读取)
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
// 3. 去重:避免不同jar包的spring.factories中重复声明同一配置类
configurations = removeDuplicates(configurations);
// 4. 排除:移除用户通过exclude属性指定的配置类(自定义排除)
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
// 5. 过滤:通过SpringFactoriesLoader加载的过滤器(如OnClassCondition)筛选配置类
configurations = getConfigurationClassFilter().filter(configurations);
// 6. 触发自动配置导入事件(供开发者监听)
fireAutoConfigurationImportEvents(configurations, exclusions);
// 7. 返回最终筛选后的配置类入口
return new AutoConfigurationEntry(configurations, exclusions);
}
第三步:加载候选配置类 getCandidateConfigurations

protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
// 核心:通过SpringFactoriesLoader加载META-INF/spring.factories中的配置类
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(
getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());
Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you "
+ "are using a custom packaging, make sure that file is correct.");
return configurations;
}
// 指定要加载的工厂类类型:EnableAutoConfiguration
protected Class<?> getSpringFactoriesLoaderFactoryClass() {
return EnableAutoConfiguration.class;
}
这一步是连接 AutoConfigurationImportSelector 和 spring.factories 的关键:SpringFactoriesLoader.loadFactoryNames会扫描类路径下所有META-INF/spring.factories文件,读取org.springframework.boot.autoconfigure.EnableAutoConfiguration对应的配置类列表。
示例一个,如下:

3.3 配置加载:SpringFactoriesLoader 与 spring.factories
SpringFactoriesLoader是 Spring 的工厂加载机制,核心逻辑是:
- 扫描类路径下所有
META-INF/spring.factories文件(仅存在于需要自动装配的 jar 包中);- 根据
EnableAutoConfiguration.class作为 key,读取对应的配置类全限定名列表;- 将这些配置类返回给
AutoConfigurationImportSelector作为候选配置类。
以 SpringBoot 2.x 的spring-boot-autoconfigure包中的spring.factories为例,核心内容如下(简化版):
# 自动配置类列表
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration
3.4 高频疑问:spring.factories 文件是每个 jar 包都有吗?
很多开发者会误以为spring.factories是所有 jar 包的 “标配”,我刚开始也以为每个jar包都有,还去这些依赖jar包的目录里翻,结果很多都没有
1.仅需自动装配的 jar 包才包含:该文件是 SpringBoot 自动装配的 “约定文件”,只有需要被 SpringBoot 自动识别并完成配置的 jar 包才会包含,主要分为两类:
- SpringBoot 官方 starter 包:如
spring-boot-starter-web、spring-boot-starter-jdbc、spring-boot-autoconfigure等;- 第三方适配 SpringBoot 的 starter 包:如
mybatis-spring-boot-starter、druid-spring-boot-starter等。
比如mp的starter包:

2.普通 jar 包无需包含:纯工具类 jar(如commons-lang3、fastjson)、未适配 SpringBoot 的原生框架 jar(如原生mybatis、jedis),因为不需要 SpringBoot 自动装配,所以不会包含该文件。
比如mybatis的jar包依赖:

简单来说:spring.factories是 “自动装配的标识文件”,只有需要 SpringBoot 主动识别并配置的 jar 包,才会在META-INF/目录下添加这个文件。
3.5 条件筛选:@Conditional 系列注解的执行
getConfigurationClassFilter().filter(configurations)这一步会触发条件注解的校验,SpringBoot 2.x 通过OnClassCondition、OnBeanCondition等实现类,校验每个候选配置类上的@Conditional系列注解:
| 条件注解 | 作用 |
|---|---|
@ConditionalOnClass |
类路径下存在指定类时,才加载该配置类(如引入了 JDBC 依赖才加载数据源配置) |
@ConditionalOnMissingBean |
容器中不存在指定 Bean 时,才创建该 Bean(用户自定义 Bean 优先级更高) |
@ConditionalOnProperty |
根据配置文件中的属性值决定是否加载(如配置了 spring.datasource 才生效) |
@ConditionalOnWebApplication |
当前项目是 Web 项目时才加载(如 DispatcherServlet 的自动配置) |
以 SpringBoot 2.x 的DataSourceAutoConfiguration为例,其核心逻辑如下:

代码注释:
@Configuration
@ConditionalOnClass({ DataSource.class, EmbeddedDatabaseType.class }) // 存在DataSource类才加载
@ConditionalOnMissingBean(type = "io.r2dbc.spi.ConnectionFactory") // 不存在R2DBC连接工厂时生效
@EnableConfigurationProperties(DataSourceProperties.class) // 绑定application.yml中的数据源配置
public class DataSourceAutoConfiguration {
// 自动配置数据源Bean的逻辑...
}
3.6 最终执行:Bean 注册到 Spring 容器
经过AutoConfigurationImportSelector筛选后的配置类,会被 Spring 的ConfigurationClassPostProcessor解析:
- 解析配置类上的
@Configuration注解;- 执行配置类中的
@Bean方法;- 将生成的 Bean(如
DataSource、JdbcTemplate)注册到 Spring 容器中;- 最终实现 “自动装配”。
这一步其实就是平时我们项目开发中定义配置类的那一步
四、SpringBoot 2.x 自动装配的灵活性:自定义配置优先
SpringBoot 2.x 的自动装配并非 “一刀切”,而是保留了极高的灵活性 ——用户自定义配置永远优先于自动配置:
- 自定义配置类:如果手动编写了
@Configuration配置类并注册了DataSourceBean,SpringBoot 会通过@ConditionalOnMissingBean跳过自动配置的数据源;- 配置属性覆盖:通过
application.yml/application.properties配置的属性(如spring.datasource.url)会覆盖自动配置的默认值;- 排除自动配置:可通过
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)排除指定的自动配置类;- 关闭自动装配:可通过配置
spring.boot.autoconfigure.enable=false全局关闭自动装配。
五、关键变化:SpringBoot 3.x 中 spring.factories 的替代方案
SpringBoot 3.x 基于 Spring Framework 6.x 构建,在自动装配的核心实现上做了重要调整 ——废弃了 spring.factories 文件,改用 SPI 机制,但AutoConfigurationImportSelector的核心逻辑框架未变:
5.1 配置文件的替换
在 SpringBoot 3.x 中,不再读取META-INF/spring.factories文件,而是将自动配置类的全限定名直接写入META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports文件中,格式为纯文本(每行一个配置类):

org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration
org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration
这种方式更符合 Java 的 SPI 规范,也简化了配置文件的解析逻辑。
5.2 核心逻辑的兼容
虽然配置文件形式变了,但AutoConfigurationImportSelector的核心流程(校验→加载→去重→排除→过滤)并未改变:
- 只是
getCandidateConfigurations方法中,读取配置的逻辑从SpringFactoriesLoader改为直接读取AutoConfiguration.imports文件;- 条件注解(
@ConditionalOnClass、@ConditionalOnMissingBean等)的使用方式和优先级完全不变;- 用户自定义配置的优先级依然高于自动配置,保证了升级的兼容性。
六、总结
核心要点
- SpringBoot 2.x 自动装配完整流程:
@EnableAutoConfiguration导入AutoConfigurationImportSelector→selectImports触发核心逻辑 →getAutoConfigurationEntry加载spring.factories中的候选配置类 → 去重 / 排除 / 条件筛选 → 注册 Bean 到容器; - spring.factories 的存在条件:仅存在于需要自动装配的 starter 包中,普通 jar 包无需包含;
- SpringBoot 3.x 关键变化:废弃
spring.factories,改用AutoConfiguration.imports文件,AutoConfigurationImportSelector核心逻辑框架不变; - 核心设计思想:约定大于配置,用户自定义配置优先级高于自动配置,兼顾便捷性和灵活性。

感兴趣的宝子可以关注一波,后续会更新更多有用的知识!!!
更多推荐



所有评论(0)