news 2026/5/11 4:27:55

第四篇:SpringBoot自动配置——约定大于配置的底层原理

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
第四篇:SpringBoot自动配置——约定大于配置的底层原理

前言

在前三篇文章中,我们拆解了Spring的IoC容器、AOP机制和SpringMVC的请求处理流程。但如果你用传统Spring开发过项目,你一定记得被XML配置支配的恐惧——DataSource要配、ViewResolver要配、Jackson转换器要配,光是配置文件就几百行。

SpringBoot改变了这一切。引入一个starter依赖,自动就能用了。面试中,自动配置是SpringBoot最核心的考点:

“@SpringBootApplication背后做了什么?”
“自动配置的原理是什么?spring.factories文件是干什么的?”
“如何自定义一个starter?”
“条件注解@ConditionalOnClass、@ConditionalOnMissingBean分别解决什么场景?”

本文拆解SpringBoot自动配置的底层原理,从启动注解一路讲到自定义starter。

本文核心问题:

  1. SpringBoot和传统Spring有什么区别?“自动配置”到底自动了什么?
  2. @SpringBootApplication背后做了什么?三个核心注解各自负责什么?
  3. @EnableAutoConfiguration是如何触发自动配置的?spring.factories文件是什么?
  4. 条件注解@ConditionalOnClass、@ConditionalOnMissingBean分别解决什么场景?它们是如何工作的?
  5. 自动配置类的执行顺序是怎样的?@AutoConfigureBefore和@AutoConfigureAfter控制什么?
  6. 如何自定义一个starter?需要哪些步骤?
  7. SpringBoot是如何自动配置SpringMVC的?为什么引入Jackson依赖就能处理JSON?
  8. 自动配置和按需配置的边界在哪?

读完本文,你将对SpringBoot自动配置拥有从启动原理到自定义starter的完整理解。


一、传统Spring vs SpringBoot

疑问:SpringBoot和传统Spring有什么区别?“自动配置”到底自动了什么?

回答:传统Spring需要开发者手动配置几乎一切。SpringBoot根据classpath中的依赖自动推测开发者意图,自动配置好所需的Bean。

1.1 传统Spring的配置

<!-- 传统Spring MVC项目需要的配置(部分) --><!-- 1. 配置DispatcherServlet --><servlet><servlet-name>dispatcher</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class></servlet><!-- 2. 配置视图解析器 --><beanclass="org.springframework.web.servlet.view.InternalResourceViewResolver"><propertyname="prefix"value="/WEB-INF/views/"/><propertyname="suffix"value=".jsp"/></bean><!-- 3. 配置Jackson消息转换器 --><beanclass="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"><propertyname="messageConverters"><list><beanclass="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"/></list></property></bean><!-- 4. 配置数据源 --><beanid="dataSource"class="com.alibaba.druid.pool.DruidDataSource"><propertyname="url"value="jdbc:mysql://localhost:3306/test"/><propertyname="username"value="root"/><propertyname="password"value="123456"/></bean><!-- 5. 配置事务管理器 --><beanid="transactionManager"class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><propertyname="dataSource"ref="dataSource"/></bean>

1.2 SpringBoot的配置

// 一个@SpringBootApplication替代了所有XML配置@SpringBootApplicationpublicclassApplication{publicstaticvoidmain(String[]args){SpringApplication.run(Application.class,args);}}// application.yml只需要关注业务配置spring:datasource:url:jdbc:mysql://localhost:3306/test username:root password:123456

传统Spring你需要显式注册每一个Bean、配置每一项能力。SpringBoot只要你引入starter依赖,它通过classpath自动感知并配置好所需的Bean。你的工作从写XML配置变成了在application.yml中声明业务参数。


二、@SpringBootApplication的三个核心注解

疑问:@SpringBootApplication只是一个注解,它怎么做到替代一堆XML配置的?

回答:@SpringBootApplication本身是一个组合注解,它合并了三个核心注解——@SpringBootConfiguration、@EnableAutoConfiguration、@ComponentScan。三者协同,完成了Bean注册、自动配置和组件扫描三件事。

@SpringBootConfiguration// ← 本质是@Configuration,声明这是配置类@EnableAutoConfiguration// ← 触发自动配置,核心中的核心@ComponentScan(// ← 扫描当前包及子包下的@Controller、@Service、@Repository等excludeFilters={@Filter(type=FilterType.CUSTOM,classes=TypeExcludeFilter.class)})public@interfaceSpringBootApplication{}

三个核心注解的分工

注解作用对应传统Spring的什么
@SpringBootConfiguration标记当前类是配置类,本质是@Configuration<context:annotation-config/>
@EnableAutoConfiguration根据classpath自动配置Bean替代开发者手动写的一大堆@Bean<bean>
@ComponentScan扫描当前包下的组件(@Controller、@Service、@Repository等)<context:component-scan>

@EnableAutoConfiguration是三者的核心——它完成了从“手动配置一切”到“自动感知、自动配置”的关键进化。


三、@EnableAutoConfiguration的底层原理

疑问:@EnableAutoConfiguration具体是怎么触发自动配置的?它怎么知道该配置什么?

回答:@EnableAutoConfiguration通过@Import注解导入AutoConfigurationImportSelector。这个selector读取spring.factories文件中声明的所有自动配置类,然后根据条件注解判断哪些配置类应该生效。

3.1 @EnableAutoConfiguration源码

@Import(AutoConfigurationImportSelector.class)// ← 核心:导入自动配置选择器public@interfaceEnableAutoConfiguration{}

@Import是Spring的一个扩展点,它的作用是将指定的类注册为Bean。通常@Import导入的是一个具体的类,但这里导入的是AutoConfigurationImportSelector——一个“选择器”,它不直接注册自己,而是计算出一组需要被注册的类。

3.2 AutoConfigurationImportSelector做了什么

// AutoConfigurationImportSelector的核心逻辑(简化)publicclassAutoConfigurationImportSelectorimplementsDeferredImportSelector,BeanClassLoaderAware,...{@OverridepublicString[]selectImports(AnnotationMetadataannotationMetadata){// 1. 读取META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports// 文件中声明的所有自动配置类List<String>configurations=getCandidateConfigurations(annotationMetadata,attributes);// 2. 根据条件注解进行过滤configurations=filter(configurations,autoConfigurationMetadata);// 3. 返回最终需要加载的自动配置类列表returnconfigurations.toArray(newString[0]);}}

这个选择器的工作分三步:读取候选配置类→根据条件注解过滤→返回最终需要注册的Bean类。它本身不配置任何东西,它只是一张“推荐清单”,由后面的条件注解决定每一条是否实际生效。

3.3 spring.factories文件

在SpringBoot 2.x中,自动配置类通过META-INF/spring.factories文件声明。SpringBoot 3.x改为META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports文件,每行一个配置类。

SpringBoot核心包中的自动配置类列表(部分):

# spring-boot-autoconfigure.jar 中的 spring.factories org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration,\ org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration,\ org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration,\ org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\ org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,\ org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration,\ ...

这就是自动配置的核心所在:SpringBoot启动时,读取所有候选配置类,然后逐一检查条件注解,决定哪些配置类应该生效。


四、条件注解——按需启用配置的过滤器

疑问:自动配置类有上百个,不可能全部启用。SpringBoot怎么判断哪个该生效?

回答:通过条件注解。每个自动配置类上都标注了@ConditionalOnXxx,Spring在加载配置类时检查这些条件——满足条件的才注册其中的Bean,不满足的直接跳过。

4.1 常用条件注解

条件注解含义典型场景
@ConditionalOnClassclasspath中有指定类时生效引入Jackson依赖→自动配置JSON转换器
@ConditionalOnMissingClassclasspath中没有指定类时生效没有引入特定依赖时退而求其次用替代方案
@ConditionalOnBean容器中有指定Bean时生效等数据源Bean注册完毕后才配置事务管理器
@ConditionalOnMissingBean容器中没有指定Bean时生效用户没有自定义ObjectMapper→用默认的
@ConditionalOnProperty配置文件中有指定属性时生效通过spring.redis.enabled=false关闭Redis
@ConditionalOnExpressionSpEL表达式结果为true时生效复杂的条件组合判断
@ConditionalOnJavaJDK版本满足条件时生效不同JDK版本用不同实现

4.2 一个实际的例子——RedisAutoConfiguration

// spring-boot-autoconfigure 中的 Redis 自动配置类@AutoConfiguration// 标记这是自动配置类@ConditionalOnClass({RedisOperations.class})// ← classpath中有RedisOperations才生效@EnableConfigurationProperties(RedisProperties.class)// 启用配置属性绑定@Import({LettuceConnectionConfiguration.class,// 引入连接配置JedisConnectionConfiguration.class})publicclassRedisAutoConfiguration{@Bean@ConditionalOnMissingBean(name="redisTemplate")// ← 用户没有自定义redisTemplate才创建publicRedisTemplate<Object,Object>redisTemplate(RedisConnectionFactoryconnectionFactory){RedisTemplate<Object,Object>template=newRedisTemplate<>();template.setConnectionFactory(connectionFactory);returntemplate;}@Bean@ConditionalOnMissingBeanpublicStringRedisTemplatestringRedisTemplate(RedisConnectionFactoryconnectionFactory){returnnewStringRedisTemplate(connectionFactory);}}

这段代码完美展示了自动配置的“按需生效”原则

  • @ConditionalOnClass:只有引入Redis依赖时才生效。如果classpath中没有RedisOperations,整个配置类都不会被加载
  • @ConditionalOnMissingBean:用户如果自己定义了redisTemplateBean,SpringBoot就不创建默认的了。这是“约定大于配置”的体现——用户可以选择覆盖默认配置,不需要时直接用默认的,需要时自定义即可

4.3 一个配置类的完整生效链路

SpringBoot启动 → 读取spring.factories → 获得候选配置类列表 → 遍历每个配置类,检查其上的条件注解 → RedisAutoConfiguration ├── 检查 @ConditionalOnClass(RedisOperations.class) │ ├── classpath中有 → 继续 │ └── classpath中没有 → 跳过这个配置类 └── 生效 → 解析其中的@Bean方法 └── 创建redisTemplate └── 检查 @ConditionalOnMissingBean ├── 容器中没有同名Bean → 创建 └── 容器中已有 → 跳过

五、配置执行顺序——@AutoConfigureBefore和@AutoConfigureAfter

疑问:多个自动配置类之间有依赖关系怎么办?比如WebMvc的自动配置需要在DispatcherServlet注册之后才执行?

回答:通过@AutoConfigureBefore和@AutoConfigureAfter声明配置类之间的顺序依赖。

// WebMvcAutoConfiguration声明它必须在几个配置类之后执行@AutoConfigureAfter(DispatcherServletAutoConfiguration.class,// DispatcherServlet注册完成后TaskExecutionAutoConfiguration.class,ValidationAutoConfiguration.class)publicclassWebMvcAutoConfiguration{// 配置HandlerMapping、HandlerAdapter、消息转换器等}

如果一个配置类的Bean依赖另一个配置类创建的Bean,需要用@AutoConfigureAfter显式声明顺序。否则可能因依赖的Bean还未创建而导致配置失败。


六、如何自定义一个starter?

疑问:项目中想把自定义的公共功能做成starter,让其他服务引入依赖就能自动生效。怎么做?

回答:一个自定义starter分为三个模块——自动配置模块、starter模块、和业务属性类。核心是把@Configuration类注册到spring.factories中,配合条件注解按需启用。

6.1 以秒杀系统的库存扣减工具为例

my-starter/ ├── my-spring-boot-starter/ # starter模块(空JAR,只放pom.xml) │ └── pom.xml # 依赖my-spring-boot-autoconfigure │ ├── my-spring-boot-autoconfigure/ # 自动配置模块 │ ├── pom.xml │ └── src/main/java/ │ ├── MyServiceAutoConfiguration.java # 自动配置类 │ └── MyProperties.java # 配置属性类 │ └── my-core/ # 核心功能模块 └── src/main/java/ └── MyService.java # 实际业务逻辑

6.2 自动配置类

@AutoConfiguration@EnableConfigurationProperties(MyProperties.class)// 绑定application.yml中的属性@ConditionalOnClass(MyService.class)// 核心类在classpath中时才生效publicclassMyServiceAutoConfiguration{@Bean@ConditionalOnMissingBean// 用户可自定义覆盖publicMyServicemyService(MyPropertiesproperties){returnnewMyService(properties.getVersion(),properties.getTimeout());}}

6.3 配置属性类

@ConfigurationProperties(prefix="my.service")publicclassMyProperties{privateStringversion="1.0";// 默认值privateinttimeout=3000;// 默认超时3秒// getter/setter}

6.4 注册配置类

META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports文件中添加:

com.example.autoconfigure.MyServiceAutoConfiguration

6.5 使用方

<!-- 其他服务引入starter --><dependency><groupId>com.example</groupId><artifactId>my-spring-boot-starter</artifactId><version>1.0.0</version></dependency>
# application.yml:自动绑定到MyPropertiesmy:service:version:"2.0"timeout:5000

starter引入后,自动配置类被注册,条件注解检查classpath→配置Bean→绑定application.yml属性→Bean创建完成,业务代码中直接注入MyService使用。开发者不需要手动写任何配置。


七、面试中这样回答

面试官:“SpringBoot的自动配置原理是什么?”

回答框架

“SpringBoot通过@EnableAutoConfiguration注解触发自动配置,它内部通过@Import导入了AutoConfigurationImportSelector。这个Selector启动时从spring.factories文件中读取所有候选的自动配置类列表,然后遍历每个配置类,检查其上标注的条件注解——比如@ConditionalOnClass判断classpath中是否有对应的依赖,@ConditionalOnMissingBean判断用户是否已经自定义了这个Bean。满足条件的配置类生效,不满足的跳过。这就是为什么引入starter依赖就能自动配置好一切。”

面试官:“如何自定义一个starter?”

回答

“分为三步。第一步写自动配置类,标注@AutoConfiguration,加上@ConditionalOnClass等条件注解,在类中定义需要自动创建的Bean,用@ConditionalOnMissingBean允许用户覆盖。第二步在spring.factories文件中注册这个自动配置类,让SpringBoot能扫描到它。第三步把自动配置模块和starter依赖打包发布——stater模块是空JAR,自动配置模块包含配置类和属性类。其他服务引入stater后,自动注册Bean并按需绑定application.yml中的配置属性。”


总结

  • @SpringBootApplication由三个核心注解组成:@SpringBootConfiguration(声明配置类)、@EnableAutoConfiguration(触发自动配置)、@ComponentScan(扫描组件)
  • @EnableAutoConfiguration通过AutoConfigurationImportSelector扫描spring.factories中声明的自动配置类,这是整个自动配置机制的入口
  • 条件注解是"按需生效"的过滤器:@ConditionalOnClass(有依赖才配)、@ConditionalOnMissingBean(用户可覆盖)是最常用的两个。条件注解让自动配置"该来的来,不该来的不来"
  • @AutoConfigureBefore/After控制配置顺序,解决配置类之间的Bean依赖关系
  • 自定义starter的三个要素:自动配置类 + spring.factories注册 + @ConditionalOnMissingBean允许覆盖
  • SpringBoot自动配置的本质:根据classpath中的依赖推测开发者的意图,自动注册所需Bean,同时保留用户覆盖的能力。约定大于配置,但不强制

下一篇预告:Spring原理(五)——Spring事务管理:@Transactional的底层实现与失效场景。拆解事务拦截器如何通过AOP实现、七种事务传播行为的适用场景、以及@Transactional在什么情况下会失效——自调用、非public方法、异常类型不匹配等。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/11 4:18:46

雷达波形生成技术:RS Pulse Sequencer应用解析

1. 雷达波形生成的技术背景与挑战现代射频测试领域面临的最大挑战之一是如何在实验室环境中准确模拟真实世界的复杂电磁环境。无论是军用雷达系统、民用航空管制设备&#xff0c;还是电子战系统&#xff0c;都需要在开发阶段验证其在复杂信号环境下的性能表现。传统解决方案主要…

作者头像 李华
网站建设 2026/5/11 4:16:39

ARMv8/v9调试系统寄存器详解与编程实践

1. ARM调试系统寄存器概述在ARMv8/v9架构中&#xff0c;调试系统寄存器是处理器调试功能的核心组件&#xff0c;它们为开发者提供了对处理器调试功能的精细控制。作为嵌入式系统开发者和安全工程师&#xff0c;深入理解这些寄存器的运作机制至关重要。调试寄存器主要分为两类&a…

作者头像 李华
网站建设 2026/5/11 4:11:41

中兴光猫终极解锁指南:3分钟掌握zteOnu完整使用技巧

中兴光猫终极解锁指南&#xff1a;3分钟掌握zteOnu完整使用技巧 【免费下载链接】zteOnu A tool that can open ZTE onu device factory mode 项目地址: https://gitcode.com/gh_mirrors/zt/zteOnu 你是否曾因中兴光猫隐藏功能无法访问而烦恼&#xff1f;普通用户界面功…

作者头像 李华