1、Spring Boot 自动装配核心源码深度剖析

Spring Boot 自动装配(Auto Configuration)是其开箱即用、简化开发的核心能力,本质是:无需手动配置大量 XML/Bean,Spring Boot 自动根据依赖、环境加载对应的配置类并注册 Bean

本文从核心注解 → 核心流程 → 关键源码 → 工作原理逐层拆解,彻底搞懂自动装配底层逻辑。

一、自动装配的核心入口:@SpringBootApplication

自动装配的起点就是启动类上的这个注解,它是一个复合注解

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration  // 🔥 自动装配的核心注解
@ComponentScan(excludeFilters = { ... })
public @interface SpringBootApplication {
}

三个核心注解分工:

  1. @SpringBootConfiguration:标记为配置类(本质是@Configuration
  2. @ComponentScan:包扫描,加载自定义 Bean
  3. @EnableAutoConfiguration:🔥 开启自动装配(核心)

二、核心注解:@EnableAutoConfiguration 源码

这个注解是自动装配的开关,源码如下:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage  // 自动配置包
@Import(AutoConfigurationImportSelector.class)  // 🔥 核心:导入自动配置选择器
public @interface EnableAutoConfiguration {
}

两个关键组件:

  1. @AutoConfigurationPackage:自动配置主类所在包及子包
  2. @Import(AutoConfigurationImportSelector.class):🔥 加载所有自动配置类

三、核心组件:AutoConfigurationImportSelector

这个类是自动装配的大脑,负责筛选、加载所有自动配置类

1. 核心方法:selectImports

@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
    // 1. 判断是否开启自动装配
    if (!isEnabled(annotationMetadata)) {
        return NO_IMPORTS;
    }
    // 2. 加载所有自动配置入口
    AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);
    // 3. 返回需要自动装配的全类名数组
    return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}

2. 核心方法:getAutoConfigurationEntry

protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
    // 1. 获取@EnableAutoConfiguration的属性(exclude等)
    AnnotationAttributes attributes = getAttributes(annotationMetadata);
    // 🔥 2. 从META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 读取所有自动配置类
    List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
    // 3. 去重
    configurations = removeDuplicates(configurations);
    // 4. 处理exclude排除的配置类
    Set<String> exclusions = getExclusions(annotationMetadata, attributes);
    checkExcludedClasses(configurations, exclusions);
    configurations.removeAll(exclusions);
    // 5. 过滤:根据条件注解(@Conditional)筛选有效配置类
    configurations = getConfigurationClassFilter().filter(configurations);
    // 6. 发布事件
    fireAutoConfigurationImportEvents(configurations, exclusions);
    // 7. 返回最终要装配的配置类
    return new AutoConfigurationEntry(configurations, exclusions);
}

3. 关键:读取自动配置类

getCandidateConfigurations 会读取 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 文件:

protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
    // 🔥 核心:SpringFactoriesLoader加载自动配置类
    List<String> configurations = ImportCandidates.load(AutoConfiguration.class, getBeanClassLoader())
        .getCandidates();
    Assert.notEmpty(configurations, ...);
    return configurations;
}
  • Spring Boot 2.7+ 用 ImportCandidates 替代了旧的 spring.factories
  • 这个文件里定义了所有官方提供的自动配置类(如DataSourceAutoConfigurationRedisAutoConfiguration
3.1 Spring Factories文件机制
3.1.1 Spring.Factories文件
  • 文件定位机制:Spring会扫描所有jar包和类路径下的META-INF/spring.factories文件
  • 多位置存储特性:该文件存在于多个jar包中:
3.1.2 键值对配置原理
  • 配置格式:采用key-value结构存储自动配置类信息
  • 典型配置项:包含如下的自动配置类映射关系:
    • org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration
    • org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration
3.1.3 核心加载流程
  • 常量定义:通过FACTORIES_RESOURCE_LOCATION常量指定文件路径为"META-INF/spring.factories"
  • 缓存机制:使用ConcurrentReferenceMap实现类加载器级别的缓存
  • 加载策略:只会加载需要的配置项,通过key进行精确匹配
  • 设计特点:支持同一key在多个jar中定义,实现配置的模块化扩展

4、核心步骤

核心步骤1:解析配置类为 BeanDefinition

Spring 后置处理器 ConfigurationClassPostProcessor 将筛选后的自动配置类,统一解析为 BeanDefinition(Bean定义信息),包含类权限、依赖、作用域、初始化方法等元数据。

  • beanClass属性:保存bean组件的class对象,用于反射实例化bean
  • scope属性:默认是singleton,也可以是prototype
  • abstractFlag属性:判断当前bean是否是抽象的
  • infer方法:容器推断销毁方法名时使用,当前检测"close"和"shutdown"方法
核心步骤2:注册 BeanDefinition 到注册表

将生成的 BeanDefinition 注册进 BeanDefinitionRegistry 容器注册表,此时仅有定义、无实例对象。

核心步骤3:解析配置类内部 @Bean 方法

递归解析自动配置类中所有 @Bean、@Conditional 注解,批量生成业务Bean的BeanDefinition并再次注册。

核心步骤4:BeanFactory 统一实例化

容器核心工厂 BeanFactory 遍历注册表中所有合法 BeanDefinition,根据定义信息完成:依赖注入、初始化、后置处理。

容器启动完成配置解析后,DefaultListableBeanFactory(核心Bean工厂)遍历所有已注册的BeanDefinition,完成实例化,Spring 高版本已废弃 Class.newInstance() 无参构造实例化方式,底层流程:

1. 解析 BeanDefinition 中的构造器、参数、依赖等元数据;        

2. 通过反射构造器实例化(优先有参构造,不再使用老旧的 `Class.newInstance()`)创建Bean原始实例;

3. 完成属性填充、依赖注入、初始化方法执行、Bean后置处理器加工;

4. 将初始化完成的单例Bean实例,存入IOC容器核心的单例池(singletonObjects 大池子)

5. 后续业务直接从IOC容器获取Bean,无需重复创建。

5、ImportSelector 局限性与 DeferredImportSelector 进阶原理

前文核心流程中自动装配的核心入口为 AutoConfigurationImportSelector,该类实现了 DeferredImportSelector 接口,而非普通的 ImportSelector。之所以做这个设计,是因为普通 ImportSelector 存在致命缺陷,无法满足 Spring Boot「用户配置优先、默认配置兜底」的核心设计思想。

5.1 普通 ImportSelector 的核心局限性

普通 ImportSelector 的执行时机极早,在所有配置类、自定义Bean扫描之前就执行导入,存在两大核心问题:

  • 无法控制Bean注册顺序:自动配置类会优先于用户自定义的 Bean、配置类注册,执行顺序不可控,容易出现配置覆盖错乱问题

  • 难以实现「用户配置优先、默认配置兜底」逻辑:框架默认配置提前注册后,用户后续自定义的同类型 Bean 无法覆盖默认 Bean,违背 Spring Boot 开箱即用、用户自定义优先的设计原则

经典业务示例:SqlSessionFactory 配置冲突问题

MyBatis 自动装配会通过普通选择器逻辑提前注册 SqlSessionFactory 默认 Bean。如果用户手动自定义了SqlSessionFactory 配置类,由于框架默认Bean先注册,容器中已存在对应Bean,用户自定义配置会失效,出现默认配置覆盖用户配置的冲突问题,严重影响业务拓展。

5.2 核心解决方案:DeferredImportSelector(延迟导入选择器)

Spring Boot 专门通过 DeferredImportSelector 解决普通选择器的缺陷,也是自动装配能实现「用户配置优先」的核心底层原理,核心特性如下:

  • 延迟导入特性:不再提前执行,在所有常规配置、用户自定义Bean处理完成后,再执行自动配置类导入

  • 分组机制:通过 getImportGroup() 方法实现配置类分组批量处理,支持有序加载、分类管理自动配置类

  1. 排序原理:通过分组可以对导入的多个Bean进行自定义排序,例如让第五个Bean排在第三个前面,第七个Bean排在第六个前面

  2. 隔离特性:分组排序只影响当前配置内部的Bean顺序,不会改变Spring容器中已有Bean的顺序

  • 条件判断适配:完美结合 @ConditionalOnBean@ConditionalOnClass 等条件注解,实现「用户有配置则用用户的,无配置则加载默认自动配置」的兜底逻辑

5.3 DeferredImportSelector 核心方法
  • selectImports():核心方法,返回需要导入的自动配置类全类名数组,和普通ImportSelector功能一致

  • getImportGroup():分组核心方法,返回自定义分组处理类,实现配置类分组、有序执行

  • getExclusionFilter():排除过滤器,支持批量剔除指定失效的自动配置类,优化配置加载效率

5.4 DeferredImportSelector 完整执行流程
  1. Spring 容器优先扫描并处理所有 用户自定义配置:包括 @Component@Bean@Configuration 等常规Bean与配置类,完成用户自定义BeanDefinition注册与实例化

  2. 所有常规配置处理完毕后,容器再统一执行 DeferredImportSelector 的导入逻辑

  3. 判断是否存在自定义 Group 分组:若返回自定义分组类,优先调用分组类的 process() 方法做批量处理、排序、过滤;若无自定义分组,则执行框架默认实现

  4. 结合 @ConditionalOnMissingBean 等条件注解:容器中已存在用户自定义Bean,则跳过默认自动配置;不存在则加载框架默认配置,完美实现用户配置优先,框架配置兜底

四、条件过滤:@Conditional 系列注解

自动装配不会无脑加载所有配置类,而是通过条件注解判断环境,按需加载:

注解 作用
@ConditionalOnClass 类路径下存在指定类时生效
@ConditionalOnMissingClass 类路径下不存在指定类时生效
@ConditionalOnBean 容器中存在指定 Bean 时生效
@ConditionalOnMissingBean 容器中不存在指定 Bean 时生效
@ConditionalOnProperty 配置文件存在指定属性时生效

示例:RedisAutoConfiguration 源码

@AutoConfiguration
@ConditionalOnClass(RedisOperations.class)  // 类路径有Redis客户端才生效
@EnableConfigurationProperties(RedisProperties.class)  // 绑定配置文件
@Import({ LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class })
public class RedisAutoConfiguration {

    @Bean
    @ConditionalOnMissingBean(name = "redisTemplate")  // 用户没自定义RedisTemplate时才创建
    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<Object, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }
}

列如Spring中默认使用Cglib作为动态代理的原因:

使用了@ConditionalOnProperty 并且matchIfMissing为true

代码如下:

五、自动装配完整流程

  • 启动类添加 @SpringBootApplication → 触发 @EnableAutoConfiguration
  • @EnableAutoConfiguration 通过 @Import 导入 AutoConfigurationImportSelector
  • AutoConfigurationImportSelector 调用 selectImports
  • META-INF/spring/...AutoConfiguration.imports 读取所有自动配置类全类名
  • 去重、处理exclude排除、通过@Conditional条件过滤
  • 符合条件的配置类注入 Spring 容器
  • 配置类中定义的@Bean被实例化,完成自动装配

大致流程图:

六、引伸出自定义Starter

自定义 Spring Boot Starter 完整实现流程

基于前面所有自动装配、延迟导入、条件注解原理,自定义 Starter 是自动装配最核心的落地实战。其本质就是:手写一套独立的自动配置类 + 配置绑定 + 自动装配注册文件,实现第三方组件的开箱即用。

6.1 自定义 Starter 核心设计思想

遵循 Spring Boot 官方规范:自动配置兜底,用户配置优先,依托 DeferredImportSelector 延迟执行特性 + @Conditional 条件注解,实现无配置自动生效、有用户配置则覆盖的效果。

6.2 自定义 Starter 标准双模块结构(官方规范)

  • xxx-spring-boot-autoconfigure(自动配置模块):存放自动配置类、属性绑定类、核心业务逻辑,是 Starter 的核心

  • xxx-spring-boot-starter(启动器依赖模块):仅做依赖聚合,空工程,专门用于给业务项目引入依赖

6.3 完整开发流程

步骤1:编写配置属性绑定类(Properties)

用于绑定 application.yml/application.properties 自定义配置,实现配置可配置、可自定义。

核心注解:@ConfigurationProperties(prefix = "自定义前缀")

步骤2:编写核心业务功能 Service

封装 Starter 的核心业务逻辑,提供对外调用的方法,供项目使用。

步骤3:编写自动配置类(AutoConfiguration)

Starter 的核心,对应 Spring 官方的 RedisAutoConfiguration、WebAutoConfiguration。

核心注解组合:

  • @AutoConfiguration:标识为自动配置类

  • @ConditionalOnClass:项目存在指定核心类时才生效

  • @EnableConfigurationProperties:绑定配置属性类

  • @ConditionalOnMissingBean用户未自定义Bean时,才自动注册默认Bean(核心:用户配置优先)

步骤4:注册自动配置入口(核心)

在资源目录创建文件:resources/META-INF/spring.factories/org.springframework.boot.autoconfigure.EnableAutoConfiguration

文件中写入自定义自动配置类的全类名,Spring Boot 启动时会通过 ImportCandidates 扫描加载该配置类,完成自动装配。

步骤5:聚合依赖、打包引用

在 starter 模块引入 autoconfigure 模块依赖,执行 Maven/Gradle 打包,业务项目直接引入 starter 依赖即可开箱即用,无需任何手动配置。

6.4 自定义 Starter 核心执行原理(串联前文知识点)

1. 业务项目引入 Starter 依赖 → 项目加载到自定义 autoconfigure 模块

2. 启动时 AutoConfigurationImportSelector 扫描所有 imports 文件,加载我们的自定义自动配置类

3. 依托 DeferredImportSelector 延迟执行特性:优先加载用户自定义 @Bean / @Configuration

4. 执行自动配置类逻辑,通过 @ConditionalOnMissingBean 判断:用户有Bean则不加载,用户无Bean则自动注册默认BeanDefinition

5. 由 BeanFactory 完成实例化,存入单例池,完成自定义组件自动装配

6.5 核心总结

自定义 Starter 本质:手写自动配置类 + 配置绑定 + 注册自动配置入口,依托延迟导入+条件注解,实现「零配置开箱即用,用户配置优先覆盖」。

更多推荐