[Java] Spring Boot Auto Configure(Spring Boot自动装配)的原理

本文深入探讨SpringBoot自动装配的工作原理,包括如何通过@EnableAutoConfiguration启用特性,以及AutoConfigurationImportSelector如何从spring.factories等文件中收集配置信息。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言


Spring Boot能帮助我们Java开发者快速开发基于Spring框架的应用,除了其作为依赖管理好帮手的一众Spring-Boot-Starter之外,其自动装配(Auto Configure)特性也起到了非常重要的作用。那么Spring Boot是如何实现自动装配的呢?本文将结合源码去讲解其原理。

版本信息


  • spring-boot-autoconfigure-2.7.5.jar
  • spring-context-5.3.23.jar
  • dubbo-3.1.1.jar
  • dubbo-spring-boot-autoconfigure-3.1.1.jar

前置知识


Spring框架里最重要的模块莫过于IoC容器,流畅阅读本文的前提是读者有IoC容器的基本概念。
我们先来梳理一些概念,Spring IoC容器里的所有组件(Component,构建完整应用的基本单元)都被称为Bean。Spring IoC容器不是神,当想要帮助其使用者实例化某个具体的Bean时,需要一些额外的信息才能做到这些额外的信息被称为Meta-data(元数据或元信息),例如多个构造器选择哪个、构造器参数信息、是否需要Autowire处理等等信息,在Spring框架里,其被抽象为BeanDefinition接口,大概长下面这个样子。
BeanDefinition结构
就像如果我们要解析JSON字符串需要调JSON解析库把其转成JSON对象再从里获取你需要的信息(数据)一样,创建实例所用的这些个BeanDefinition信息是不会自己跑到Spring IoC容器里的,这需要Spring IoC容器自己去收集,收集BeanDefinition信息是Spring IoC容器的几大主要工作之一。那么Spring框架是如何收集这些信息的呢?

Spring框架如何收集BeanDefinition信息?

既然要收集信息,就不得不提信息载体,信息载体是承载信息(数据)的东西,但凡一个物体能表示1bit的信息都能被视为信息的载体,可见信息的载体有很多种,就例如各种格式的文本文件、序列化后的二进制文件、Java内存里的(Java注解、类名、方法名、参数名、参数类型)等等都是信息的载体。那么相信大家已经猜到了,Spring收集BeanDefinition信息的方式大家至少可以有这么几种:

  • XML配置:Spring所谓的XML config方式,通过XML文本文件存储信息。
  • Java配置:Spring所谓的Java config方式,利用反射API收集注解、类名、方法名、参数名、参数类型携带的信息。

Java配置又可以细分成几种:

  • 如@Component、@Service、@Controller之类的通常是Spring通过反射API和缺省信息去收集BeanDefinition信息。
  • 如@Configuration之类的则是由开发者自主装配Bean。Spring不需要费太大力气便能利用广大开发者写的Bean方法去实例化某个Bean。

除开上面两个,还有如ImportSelector接口、ImportBeanDefinitionRegistrar接口这两种方式:

  • ImportBeanDefinitionRegistrar接口:模块开发者直接向IoC容器里注册BeanDefinition,如dubbo里就用了这种方式。
  • ImportSelector接口:递归地注册ImportSelector#SselectImports方法所发现的所有ImportSelector、ImportBeanDefinitionRegistrar、@Configuration类相关的BeanDefinition。

虽然再细分ImportSelector还能分出DeferredImportSelector,不过这不在本文的讨论范畴之内,咱们先忽略它。

Spring Boot 自动装配的原理


Spring Boot自动装配本质就是向IoC容器提供BeanDefinition的过程。其用到了我们上述的四种Java Config中的后三种。

  • ImportSelector接口
  • ImportBeanDefinitionRegistrar接口
  • @Configuration类

Spring框架的Context核心模块提供了这些功能

上面提到的分三类的处理方式并不是Spring Boot提供的,而是Spring Context提供的。
你可以在下面方法里看到其处理的逻辑:

Spring-Context-5.3.23.jar文件的
org.springframework.context.annotation.ConfigurationClassParser类的
processImports方法
private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
			Collection<SourceClass> importCandidates, Predicate<String> exclusionFilter,
			boolean checkForCircularImports) {
	/* 省略 */
	for (SourceClass candidate : importCandidates) {
		if (candidate.isAssignable(ImportSelector.class)) { 
			// Candidate class is an ImportSelector -> delegate to it to determine imports
			/* 省略 */ 
		} else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
			// Candidate class is an ImportBeanDefinitionRegistrar ->
			// delegate to it to register additional bean definitions
			/* 省略 */
		} else {
			// Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar ->
			// process it as an @Configuration class
			/* 省略 */
		}
	}
	/* 省略 */
}

Spring Boot则利用了Spring Context提供的功能来实现自动装配。

@EnableAutoConfiguration:Spring Boot开启自动装配特性的注解

想要Spring Boot开启自动装配特性,我们是需要在程序入口类使用@EnableAutoConfiguration注解来开启自动装配功能,也许大家没怎么见过这个注解,不过一般使用了组合注解@SpringBootApplication的话就是等于开启了@EnableAutoConfiguration的,@SpringBootApplication注解的定义如下:

SpringBootApplication注解

@EnableAutoConfiguration本身也是一个组合注解,定义如下:

EnableAutoConfiguration注解
@Import(AutoConfigurationImportSelector.class)则是其最重要的部分,不难看出其核心是一个我们上面提到过的ImportSelector,@Import注解是向IoC容器里引入一个Bean,这里就引入了AutoConfigurationImportSelector类。

Spring Boot提供的AutoConfigurationImportSelector类干了什么?

相信大家都对spring.factories文件或多或少都有耳闻。对,你猜的没错,简单来AutoConfigurationImportSelector类主要干了两件事

  1. 利用SpringFactoriesLoader类从ClassPath上所有的META-INF/spring.factories文件读取上述三种自动配置类的信息(类名)。

SpringFactoriesLoader源码

  1. 利用ImportCandidates类从ClassPath上所有的META-INF/spring/org.springframework.boot.autoconfiguration.AutoConfiguration.imports文件里读取上述三种自动配置类的信息(类名)。

ImportCandidates源码

AutoConfigurationImportSelector类种利用这两个类的源码如下,第二种方式是较新的,而spring.factories文件的方式则是较老的一种实现。目前在笔者的spring boot 2.7.5版本里是两者都支持的(也就是提供了向下兼容性)。可以看到下方源码中,先调用了SpringFactoriesLoader,再调用了ImportCandidates。
AutoConfigurationImportSelector源码

AutoConfigurationImportSelector支持的两类文件长什么样?


在上一节我们提到了AutoConfigurationImportSelector类支持两类文件来做扩展,分别是:

  • 较老的META-INF/spring.factories文件
  • 较新的META-INF/spring/org.springframework.boot.autoconfiguration.AutoConfiguration.imports文件

1. META-INF/spring.factories文件

第一个是较老的META-INF/spring.factories文件,其本质是个Properties格式的文本文件。内容就是KEY=VALUE。
就比如说我们看一下dubbo-spring-boot-autoconfigure-3.1.1.jar里的这个文件就长这样:

dubbo的spring.factories文件

2. META-INF/spring/org.springframework.boot.autoconfiguration.AutoConfiguration.imports文件

第二个是比较新的META-INF/spring/org.springframework.boot.autoconfiguration.AutoConfiguration.imports,其就是个普通的换行符分割文本文件
我们看一下spring-boot-autoconfigure-2.7.5.jar里的这个文件长这样:

新文件

文件内容

两种文件的内容普遍都是@Configuration类的全名(包名+类名),这里的数据本质是字符串,读到内存里还是需要利用反射API转换成Class<?>实例再开始使用的,就是由ConfigurationClassParser$DeferredImportSelectorHandler的processGroupImports方法来实现的。可以看到内部调用了我们先前提到的processImports方法。
processGroupImports

反射API具体使用的地方就是上面代码里的调用asSourceClass方法了:

asSourceClass方法

结语


通过源码分析,我们可以看到Spring Boot利用了Spring Context提供的加载机制,其先利用@Import把自身最关键的组件AutoConfigurationImportSelector引入到容器里,并且引入ImportSelector是会递归引入AutoConfigurationImportSelector在两种文件里找到的所有的类,也是这种动态地加载所有这两类文件的机制是Spring Boot自动装配实现扩展性的核心。使得其他项目、组件的开发者可以利用这个扩展机制(如编写自己的spring.factories文件、@Configuration类等)去支持或叫实现自动装配。但不难看出Spring Boot虽然实现了自动装配,但实际的装配工作(@Configuration类、ImportSelector、ImportBeanDefinitionRegistrar的编码工作)还是需要由对应的项目开发者去实现的,比如dubbo就是自己实现的相应的spring boot自动装配类。

<think>嗯,用户之前问了本地缓存和全局缓存的区别,现在又转向了Spring Boot的装配原理。看来他们可能是在学习Spring Boot,或者在做相关项目,需要深入理解其内部机制。之前的回答结构很清晰,用户可能希望同样详细的解答,所以得保持类似的格式。 首先,用户问的是Spring Boot的装配原理,应该包括自动配置、条件注解、starter机制这些核心点。需要先明确用户的基础,可能他们已经有Spring的基础,但需要更深入的理解。得从基础概念讲起,再分点详细说明。 记得用户可能需要知道Spring Boot如何简化配置,自动配置是怎么工作的,以及starter的作用。同时,用户可能对背后的原理感兴趣,比如@SpringBootApplication注解背后的机制,SpringFactoriesLoader的使用,条件注解如何起作用,还有可能想了解自动配置的执行流程。 还要考虑用户的实际应用场景,比如他们可能在开发中遇到配置问题,或者想要自定义starter,这时候了解原理会有帮助。需要举一些例子,比如用代码片段说明自动配置类,或者starter的结构,这样更直观。 另外,用户之前的问题对比了本地和全局缓存,可能他们现在的问题也是想比较传统SpringSpring Boot的配置方式,所以可以适当提到传统Spring需要手动配置,而Spring Boot通过自动配置减少工作量。 需要避免过于技术化的术语,但也要准确。比如解释@ConditionalOnClass这样的条件注解时,要说明它的作用,以及为什么重要。同时,注意结构清晰,分点列出,便于阅读。 可能用户还会想知道如何排除自动配置,或者自定义配置,所以应该在回答中涵盖这些内容,比如使用exclude属性,或者如何编写自己的自动配置类。 最后,总结部分需要强调Spring Boot如何通过约定大于配置和自动装配简化开发,这样用户能有一个整体的理解。可能用户需要这些知识来优化他们的项目配置,或者解决一些依赖问题,所以实际应用建议也很重要。 检查一下是否有遗漏的关键点,比如SPI机制、Spring Boot启动流程中的自动配置触发时机,还有组合注解的使用。确保每个部分都逻辑连贯,例子恰当,帮助用户从理论到实践全面理解装配原理。</think>--- ### Spring Boot 装配原理核心解析 Spring Boot自动装配Auto-Configuration)是其简化开发的核心机制,通过**约定大于配置**的理念,自动加载所需的 Bean 和组件。以下是其核心原理与实现逻辑: --- #### 1. **核心注解:`@SpringBootApplication`** ```java @SpringBootApplication public class MyApplication { public static void main(String[] args) { SpringApplication.run(MyApplication.class, args); } } ``` - **组合注解**:实际包含三个关键注解: - `@SpringBootConfiguration`:标记当前类为配置类(等价于 `@Configuration`)。 - `@EnableAutoConfiguration`:**启用自动装配**的核心注解。 - `@ComponentScan`:扫描当前包及其子包下的组件(如 `@Component`、`@Service`)。 --- #### 2. **自动装配触发机制** **关键流程**: 1. **启动类加载**:通过 `SpringApplication.run()` 启动应用。 2. **`@EnableAutoConfiguration` 生效**:触发 Spring Boot 的自动配置逻辑。 3. **加载 `META-INF/spring.factories`**:扫描所有依赖 JAR 中的该文件,获取预定义的**自动配置类**。 **示例(spring-boot-autoconfigure 中的 `spring.factories` 片段)**: ```properties # Auto Configure org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration,\ org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\ ... ``` --- #### 3. **条件装配(Conditional Loading)** Spring Boot 通过 `@Conditional` 系列注解**按需加载配置**,避免无效 Bean 的注入。 | **常用条件注解** | **触发条件** | |----------------------------|------------------------------------------| | `@ConditionalOnClass` | 类路径中存在指定类时生效(如存在 `DataSource.class` 才加载数据源配置) | | `@ConditionalOnMissingBean` | 容器中不存在指定 Bean 时生效(允许用户自定义 Bean 覆盖默认配置) | | `@ConditionalOnProperty` | 配置文件中存在指定属性时生效(如 `spring.datasource.url`) | **示例(`DataSourceAutoConfiguration` 片段)**: ```java @Configuration @ConditionalOnClass({ DataSource.class, EmbeddedDatabaseType.class }) @EnableConfigurationProperties(DataSourceProperties.class) public class DataSourceAutoConfiguration { // 根据条件创建 DataSource Bean } ``` --- #### 4. **自动配置类的执行逻辑** 1. **加载配置类**:根据 `spring.factories` 中的配置类列表,按顺序加载。 2. **条件检查**:通过 `@Conditional` 注解过滤出符合条件的配置类。 3. **注册 Bean**:在符合条件的配置类中,通过 `@Bean` 方法向容器注册组件。 **示例(简化版 `DispatcherServletAutoConfiguration`)**: ```java @AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE) @Configuration @ConditionalOnWebApplication(type = Type.SERVLET) @ConditionalOnClass(DispatcherServlet.class) @AutoConfigureAfter(ServletWebServerFactoryAutoConfiguration.class) public class DispatcherServletAutoConfiguration { @Bean public DispatcherServlet dispatcherServlet() { return new DispatcherServlet(); } // 其他相关 Bean 的配置 } ``` --- #### 5. **Starter 机制** **Starter 的作用**:通过依赖传递,自动引入一组关联的库和配置。 | **Starter 名称** | **功能** | |---------------------------|----------------------------| | `spring-boot-starter-web` | 引入 Spring MVC、Tomcat 等 Web 相关依赖 | | `spring-boot-starter-data-jpa` | 引入 JPA、Hibernate 等数据库依赖 | **原理**: - 每个 Starter 包含一个 `spring.factories` 文件,定义其提供的自动配置类。 - 依赖 Starter 后,Spring Boot 自动合并所有 `spring.factories` 中的配置类。 --- #### 6. **自定义自动配置** **步骤**: 1. 创建配置类,使用 `@Configuration` 和 `@Conditional` 注解。 2. 在 `src/main/resources/META-INF/spring.factories` 中声明配置类: ```properties org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ com.example.MyCustomAutoConfiguration ``` 3. 打包为 JAR,供其他项目依赖使用。 **示例(自定义 Redis 配置)**: ```java @Configuration @ConditionalOnClass(RedisConnectionFactory.class) @EnableConfigurationProperties(RedisProperties.class) public class MyRedisAutoConfiguration { @Bean @ConditionalOnMissingBean public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) { RedisTemplate<String, Object> template = new RedisTemplate<>(); template.setConnectionFactory(factory); return template; } } ``` --- ### 关键总结 | **机制** | **作用** | |---------------------|--------------------------------------| | `@EnableAutoConfiguration` | 触发自动配置流程,加载所有符合条件的配置类 | | `spring.factories` | 定义自动配置类的注册入口 | | 条件注解(`@ConditionalOnXxx`) | 按需加载配置,避免冗余 Bean 的注入 | | Starter | 通过依赖管理简化库的集成,实现“开箱即用” | --- ### 调试与排除自动配置 1. **查看生效的自动配置类**: 启动时添加 `--debug` 参数,控制台会输出: - `Positive matches`(已生效的配置类)。 - `Negative matches`(未生效的配置类及原因)。 2. **排除特定自动配置**: ```java @SpringBootApplication(exclude = { DataSourceAutoConfiguration.class }) public class MyApplication { ... } ``` --- ### 实际应用建议 1. **优先使用默认配置**:Spring Boot 的自动配置已覆盖大多数常见场景。 2. **谨慎覆盖默认 Bean**:通过 `@ConditionalOnMissingBean` 实现自定义扩展。 3. **理解条件注解逻辑**:避免因依赖缺失导致配置不生效。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值