在前面十多篇里我们拆解了 IoC 容器、Spring MVC、AOP、事务管理——这些是 Spring 框架的核心能力。但你有没有想过一个问题在 Spring Boot 出现之前配置这些东西有多麻烦你需要写web.xml配置 DispatcherServlet需要写applicationContext.xml配置数据源、事务管理器、视图解析器需要写spring-mvc.xml配置组件扫描……一个项目光 XML 配置文件就有三四个加起来几百行。Spring Boot 的出现把这一切都简化成了几行application.yml和一个SpringBootApplication注解。这一篇我们把 Spring Boot 自动配置的底层逻辑拆开来看——从SpringBootApplication的组成到EnableAutoConfiguration的工作原理再到spring.factories和AutoConfiguration.imports的加载机制。学习目标理解 Spring Boot“约定优于配置”的设计哲学掌握SpringBootApplication组合注解的三个核心成员深入理解EnableAutoConfiguration的工作原理了解spring.factories/AutoConfiguration.imports文件的作用掌握Conditional条件注解家族的使用了解如何编写自定义 Starter正文一、“约定优于配置”是什么“约定优于配置”Convention over Configuration是 Spring Boot 最核心的设计理念。它的意思是框架基于合理的默认约定来工作开发者只需要在偏离约定时才进行显式配置。这句话听起来有点抽象我们用一个具体的例子来说明。在 Spring MVC 中视图解析器有一个常见的配置你需要告诉 SpringJSP 文件放在哪里、后缀是什么。!-- 传统的 Spring MVC 配置 --beanclassorg.springframework.web.servlet.view.InternalResourceViewResolverpropertynameprefixvalue/WEB-INF/views//propertynamesuffixvalue.jsp//bean这段配置告诉 Spring视图文件在/WEB-INF/views/目录下后缀是.jsp。Spring Boot 的约定是如果你用 Thymeleaf模板文件放在src/main/resources/templates/下后缀是.html。如果你遵循这个约定就不需要任何配置。这就是“约定优于配置”——框架有一个默认的约定你遵循它就能零配置工作。只有当你需要偏离约定时比如想把模板放在其他目录才需要显式配置。Spring Boot 中的典型约定约定项Spring Boot 默认值配置文件位置src/main/resources/application.yml静态资源位置src/main/resources/static/或public/模板文件位置src/main/resources/templates/组件扫描路径启动类所在包及其子包嵌入式容器端口8080数据库连接池HikariCP这些约定不是“写死的”而是可覆盖的——你可以在application.yml中修改它们。但如果你不修改框架就用默认值帮你工作。从“XML 地狱”到“零配置”在 Spring Boot 之前一个典型的 Spring 项目需要这些配置文件web.xml配置 DispatcherServlet、Filter、ListenerapplicationContext.xml配置数据源、事务管理器、Service 扫描spring-mvc.xml配置视图解析器、HandlerMapping、组件扫描mybatis-config.xml配置 MyBatis 设置加起来少则几百行多则上千行。Spring Boot 用自动配置取代了这些 XML——你只需要引入对应的 Starter框架就会根据类路径中的依赖自动推断并应用合适的配置。二、SpringBootApplication 拆解三个注解的组合SpringBootApplication是 Spring Boot 最核心的注解。我们点开它的源码看看Target(ElementType.TYPE)Retention(RetentionPolicy.RUNTIME)DocumentedInheritedSpringBootConfigurationEnableAutoConfigurationComponentScan(excludeFilters{Filter(typeFilterType.CUSTOM,classesTypeExcludeFilter.class),Filter(typeFilterType.CUSTOM,classesAutoConfigurationExcludeFilter.class)})publicinterfaceSpringBootApplication{// ...}SpringBootApplication是一个组合注解它聚合了三个核心注解注解作用SpringBootConfiguration表明这是一个 Spring Boot 配置类等同于ConfigurationEnableAutoConfiguration启用自动配置——这是 Spring Boot 自动配置的总开关ComponentScan启用组件扫描默认扫描当前类所在包及其子包SpringBootConfiguration它本质上就是Configuration只是 Spring Boot 单独定义了一个注解来标识“这是一个 Spring Boot 配置类”。ComponentScan默认扫描启动类所在包及其子包下的所有Component以及Service、Controller、Repository等衍生注解。这意味着你放在启动类所在包外面的组件不会被扫描到——这是新手常踩的坑之一。EnableAutoConfiguration这是自动配置的核心。它告诉 Spring Boot“根据类路径中的依赖自动推断并应用合适的配置。”三、EnableAutoConfiguration 的奥秘EnableAutoConfiguration是 Spring Boot 自动配置的总开关。我们来看它的源码Target(ElementType.TYPE)Retention(RetentionPolicy.RUNTIME)DocumentedInheritedAutoConfigurationPackageImport(AutoConfigurationImportSelector.class)publicinterfaceEnableAutoConfiguration{Class?[]exclude()default{};String[]excludeName()default{};}EnableAutoConfiguration做了两件关键的事情第一件AutoConfigurationPackage这个注解通过Import(AutoConfigurationPackages.Registrar.class)导入了一个 Registrar它会记录启动类所在的包路径。这个包路径随后会被用于ComponentScan的默认扫描范围。第二件Import(AutoConfigurationImportSelector.class)这是自动配置的核心机制。AutoConfigurationImportSelector实现了ImportSelector接口它的作用是在 Spring 容器启动时动态加载所有自动配置类。AutoConfigurationImportSelector的工作流程是这样的Spring 在解析Import时调用AutoConfigurationImportSelector.selectImports()方法该方法读取配置文件获取所有自动配置类的全限定名列表对这些配置类进行去重和排除处理根据exclude和excludeName属性返回最终需要加载的配置类名称数组Spring 将这些配置类作为 Bean 定义加载到容器中关键认知EnableAutoConfiguration本身不包含任何配置类——它只是一个“开关”。真正干活的是AutoConfigurationImportSelector它负责发现并加载所有的自动配置类。四、spring.factories 的约定自动配置类的“清单”那么AutoConfigurationImportSelector是从哪里读取自动配置类的呢答案是META-INF/spring.factories文件。在 Spring Boot 2.x 及之前的版本中每个 Starter 的 JAR 包中都包含一个META-INF/spring.factories文件。这个文件的内容格式是keyvalue其中org.springframework.boot.autoconfigure.EnableAutoConfiguration这个 key 对应的 value 就是自动配置类的全限定名列表。# META-INF/spring.factories 示例Spring Boot 2.x org.springframework.boot.autoconfigure.EnableAutoConfiguration\ org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration,\ org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\ org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfigurationSpring Boot 3.x 的变化从 Spring Boot 3.0 开始spring.factories文件被废弃了取而代之的是META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports文件。新的文件格式更简洁每行一个配置类的全限定名不需要 key-value 结构。# META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration为什么要改变spring.factories文件被用于多种目的自动配置、监听器、初始化器等所有配置都挤在一个文件里容易混乱。新的.imports文件职责更单一——只用于自动配置类的声明更加清晰和模块化。兼容性说明如果你在 Spring Boot 3.x 项目中仍然使用spring.factories来声明自动配置类它们不会被加载。必须迁移到新的.imports文件格式。五、Conditional 条件配置为什么自动配置不会“过度配置”你可能会问Spring Boot 加载了这么多自动配置类难道它们全都生效吗答案是否定的。如果所有自动配置类都生效你的应用会启动得非常慢而且会加载大量不需要的 Bean。Spring Boot 通过Conditional系列注解来控制自动配置类是否生效。每个自动配置类上都标注了一个或多个Conditional注解只有条件满足时这个配置类才会被加载。最常用的条件注解注解条件ConditionalOnClassclasspath 中存在指定的类时才生效ConditionalOnMissingClassclasspath 中不存在指定的类时才生效ConditionalOnBean容器中存在指定的 Bean 时才生效ConditionalOnMissingBean容器中不存在指定的 Bean 时才生效ConditionalOnProperty配置文件中存在指定的属性且值匹配时才生效ConditionalOnWebApplication当前应用是 Web 应用时才生效ConditionalOnMissingBean的特殊意义这个注解是 Spring Boot 自动配置可覆盖性的关键。它的含义是只有当开发者没有自定义该类型的 Bean 时自动配置才会创建默认的 Bean。举个例子DataSourceAutoConfiguration中会创建一个默认的DataSourceBean但它的定义上标注了ConditionalOnMissingBean(DataSource.class)。这意味着如果你在项目中没有定义自己的DataSourceSpring Boot 会根据application.yml中的配置自动创建一个如果你在项目中定义了自己的DataSourceSpring Boot 的自动配置就不会覆盖它这就是“约定优于配置”的底层实现——框架提供默认值但你可以随时覆盖。常见的自动配置加载顺序控制当多个自动配置类之间有依赖关系时可以通过AutoConfigureBefore和AutoConfigureAfter来控制加载顺序。例如DataSourceAutoConfiguration需要先于JdbcTemplateAutoConfiguration加载因为后者依赖前者创建的数据源。六、自定义 Starter 实战把自动配置打包成可复用的模块理解了自动配置的原理我们就可以自己动手写一个Starter了。Starter 的组成一个标准的 Spring Boot Starter 通常包含两个模块xxx-spring-boot-starter依赖管理模块负责引入所需的依赖和autoconfigure模块xxx-spring-boot-autoconfigure自动配置模块包含配置类和自动配置声明开发步骤以 Spring Boot 3.x 为例第一步创建 autoconfigure 模块编写自动配置类packagecom.example.greeting.autoconfigure;importorg.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;importorg.springframework.boot.context.properties.EnableConfigurationProperties;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;ConfigurationEnableConfigurationProperties(GreetingProperties.class)publicclassGreetingAutoConfiguration{BeanConditionalOnMissingBeanpublicGreetingServicegreetingService(GreetingPropertiesproperties){returnnewGreetingService(properties.getPrefix(),properties.getSuffix());}}第二步定义配置属性类packagecom.example.greeting.autoconfigure;importorg.springframework.boot.context.properties.ConfigurationProperties;ConfigurationProperties(prefixgreeting)publicclassGreetingProperties{privateStringprefixHello;privateStringsuffix!;// getter / setter 省略}第三步声明自动配置类Spring Boot 3.x 方式在src/main/resources/META-INF/spring/目录下创建org.springframework.boot.autoconfigure.AutoConfiguration.imports文件com.example.greeting.autoconfigure.GreetingAutoConfiguration第四步创建 starter 模块可选如果你希望用户只引入一个依赖就能使用可以创建一个 starter 模块在它的pom.xml中引入 autoconfigure 模块dependencygroupIdcom.example/groupIdartifactIdgreeting-spring-boot-autoconfigure/artifactId/dependency使用方式其他项目引入这个 starter 后只需要在application.yml中配置greeting:prefix:你好suffix:~然后就可以通过Autowired注入GreetingService使用了——完全不需要任何额外的配置。代码示例示例一查看 Spring Boot 自动配置报告Spring Boot 提供了一个非常有用的调试工具——自动配置报告。它告诉你哪些自动配置类生效了哪些没有以及没有生效的原因。方式一启动时添加--debug参数在启动应用时添加--debug参数java-jarmyapp.jar--debug或者在 IDE 中在启动配置的 Program arguments 中添加--debug。方式二在application.yml中配置debug:true启动后控制台会输出一份详细的自动配置报告 CONDITIONS EVALUATION REPORT Positive matches: ----------------- DataSourceAutoConfiguration matched: - ConditionalOnClass found required classes org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType (OnClassCondition) - ConditionalOnMissingBean (types: javax.sql.DataSource; SearchStrategy: all) did not find any beans (OnBeanCondition) Negative matches: ----------------- JdbcTemplateAutoConfiguration: - ConditionalOnClass required classes org.springframework.jdbc.core.JdbcTemplate found; - ConditionalOnSingleCandidate (types: javax.sql.DataSource) did not find a primary bean from dataSource (OnBeanCondition)Positive matches自动配置生效的类及其原因Negative matches自动配置未生效的类及其原因这份报告是排查自动配置问题的第一手工具。如果你引入了一个 Starter 但它的功能没有生效先看这份报告——它会告诉你哪个条件不满足。示例二自定义一个简单的 Starter我们来完整实现一个“问候服务”的 Starter。项目结构greeting-spring-boot-starter/ ├── greeting-spring-boot-autoconfigure/ │ ├── src/main/java/com/example/greeting/autoconfigure/ │ │ ├── GreetingService.java │ │ ├── GreetingProperties.java │ │ └── GreetingAutoConfiguration.java │ └── src/main/resources/META-INF/spring/ │ └── org.springframework.boot.autoconfigure.AutoConfiguration.imports └── greeting-spring-boot-starter/ └── pom.xml1. GreetingService业务类packagecom.example.greeting.autoconfigure;publicclassGreetingService{privatefinalStringprefix;privatefinalStringsuffix;publicGreetingService(Stringprefix,Stringsuffix){this.prefixprefix;this.suffixsuffix;}publicStringgreet(Stringname){returnprefix namesuffix;}}2. GreetingProperties配置属性类packagecom.example.greeting.autoconfigure;importorg.springframework.boot.context.properties.ConfigurationProperties;ConfigurationProperties(prefixgreeting)publicclassGreetingProperties{privateStringprefixHello;privateStringsuffix!;publicStringgetPrefix(){returnprefix;}publicvoidsetPrefix(Stringprefix){this.prefixprefix;}publicStringgetSuffix(){returnsuffix;}publicvoidsetSuffix(Stringsuffix){this.suffixsuffix;}}3. GreetingAutoConfiguration自动配置类packagecom.example.greeting.autoconfigure;importorg.springframework.boot.autoconfigure.condition.ConditionalOnClass;importorg.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;importorg.springframework.boot.context.properties.EnableConfigurationProperties;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;ConfigurationConditionalOnClass(GreetingService.class)EnableConfigurationProperties(GreetingProperties.class)publicclassGreetingAutoConfiguration{BeanConditionalOnMissingBeanpublicGreetingServicegreetingService(GreetingPropertiesproperties){returnnewGreetingService(properties.getPrefix(),properties.getSuffix());}}4. 声明自动配置类Spring Boot 3.x 方式在src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports中写入com.example.greeting.autoconfigure.GreetingAutoConfiguration5. starter 模块的 pom.xmldependencygroupIdcom.example/groupIdartifactIdgreeting-spring-boot-autoconfigure/artifactIdversion1.0.0/version/dependency使用方引入 starter 后在application.yml中配置greeting:prefix:你好suffix:在代码中注入使用RestControllerpublicclassHelloController{AutowiredprivateGreetingServicegreetingService;GetMapping(/hello)publicStringhello(RequestParamStringname){returngreetingService.greet(name);// 输出你好 张三}}关键观察ConditionalOnMissingBean保证了如果使用方自己定义了GreetingService的 Bean自动配置不会覆盖EnableConfigurationProperties让application.yml中的greeting.*配置自动绑定到GreetingProperties对象使用方零配置即可使用——引入依赖、注入 Bean、直接调用新手错误 vs 正确姿势错误表象根本原因正确姿势引入依赖后自动配置未生效功能没有加载自动配置的条件不满足如缺少某个类、某个 Bean 已存在、某个配置属性不匹配启动时添加--debug查看自动配置报告找到Negative matches中对应的原因自定义的配置被 Spring Boot 默认配置覆盖了未使用ConditionalOnMissingBean保护自定义 Bean在Bean方法上添加ConditionalOnMissingBean让自动配置仅在用户未定义时才生效Spring Boot 3.x 项目中自定义 Starter 的自动配置不生效仍然使用META-INF/spring.factories声明自动配置类Spring Boot 3.x 必须使用META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports文件ComponentScan扫描不到某些包中的 BeanSpringBootApplication默认只扫描启动类所在包及其子包使用ComponentScan(basePackages {com.example.module1, com.example.module2})显式指定扫描范围在 Spring Boot 2.x 和 3.x 之间切换时自动配置行为不一致两个版本的自动配置加载机制不同spring.factoriesvs.imports确认项目使用的 Spring Boot 版本按对应版本的规范配置疑难深度追问Q1spring.factories和AutoConfiguration.imports有什么区别spring.factories是 Spring Boot 2.x 及之前版本使用的通用配置文件采用 key-value 格式一个文件同时用于自动配置、监听器、初始化器等多种 SPI 扩展点。AutoConfiguration.imports是 Spring Boot 3.x 引入的专用配置文件每行一个配置类全限定名职责更单一。Spring Boot 3.x 中spring.factories中的EnableAutoConfiguration条目不再被读取。Q2如果多个自动配置类有冲突Spring Boot 如何决定加载顺序通过三个注解控制AutoConfigureBefore指定在某个配置类之前加载AutoConfigureAfter指定在某个配置类之后加载AutoConfigureOrder指定加载顺序的优先级数字越小越先加载Spring Boot 在加载自动配置类时会解析这些注解对配置类进行排序后再依次加载。Q3为什么 Spring Boot 的自动配置要使用ConditionalOnMissingBean这个设计有什么好处ConditionalOnMissingBean实现了“可覆盖的默认值”设计模式。它带来的好处灵活性开发者可以完全控制 Bean 的创建逻辑不被框架的默认实现绑定渐进式学习新手可以完全依赖自动配置开箱即用高手可以精细覆盖按需定制模块化多个 Starter 可以共存通过ConditionalOnMissingBean避免 Bean 重复定义导致冲突思考与延伸动手验证在 Spring Boot 项目中设置debug: true启动后查看自动配置报告找到 3 个 Positive matches 和 3 个 Negative matches理解它们生效/不生效的原因。思考题ConditionalOnMissingBean和Primary都能解决“多个同类型 Bean 冲突”的问题它们的使用场景有什么不同延伸阅读Spring Boot 官方文档的 “Developing Auto-configuration” 章节对自定义 Starter 有完整的指南。另外AutoConfigurationImportSelector的源码是理解自动配置加载流程的最佳入口。参考与延伸阅读Spring Boot.Developing Auto-configuration and Using Conditions. Spring Boot DocumentationSpring Boot.Auto-configuration. Spring Boot Documentation腾讯云.Spring Boot自动配置深度解析EnableAutoConfiguration与AutoConfigurationImportSelector源码解密. 2025-08-27阿里云.SpringBoot自动装配机制. 2025-12-11腾讯云.什么是约定优于配置自动配置的原理是什么. 2025-12-18阿里云.SpringBoot自动配置的原理是什么. 2025-07-15阿里云.SpringBoot中如何自定义starter. 2025-12-12腾讯云.Spring Boot Starter 自定义开发封装中间件配置. 2026-02-19