SPRING BOOT · AUTO-CONFIGURATION · JDK 8 / 17
加一行依赖,为什么就能直接用?
Spring Boot 是一支拎包入住的装修队。你选礼包,它照着一份清单,由检查员挨个确认后,把该装的 Bean 装好。
Starterpom.xml 里加一行,一整套零件就送到 classpath 上。
spring-boot-starter-xxxAutoConfiguration一百多张安装卡片。每张写着:满足什么条件,就装哪些 Bean。
登记在 AutoConfiguration.imports@Conditional装之前挨个问:零件到了吗?你自己装过没?开关开了吗?
@ConditionalOnXxx 一家子一张图看原理
总开关拆开是三个注解。真正干活的是第三个,它带来一个“选择器”,负责下面整个漏斗。
@SpringBootConfiguration它自己就是个配置类@ComponentScan扫描你自己的包,先登记你的 Bean@EnableAutoConfiguration打开自动配置
@Import(AutoConfigurationImportSelector)选择器:读清单、筛选、排序
META-INF/spring/…AutoConfiguration.imports Boot 2:spring.factories@SpringBootApplication(exclude = …) 或 spring.autoconfigure.excludespring-autoconfigure-metadata.properties@AutoConfiguration(after = DataSourceAutoConfiguration.class)装修现场
左边勾选你做了什么,右边看 8 张常见的清单卡片谁装上、谁跳过、谁让位给你。默认是一个典型的 Web + 数据库项目。
pom.xml 里的礼包
application.yml
你自己的代码
自动配置在启动的哪一步
SpringApplication.run() 的八站。你的 Bean 在第 4 站登记,自动配置在第 5 站才登场。
- 1判断应用类型看 classpath:Servlet、Reactive 还是非 Web
- 2准备环境读 application.yml、环境变量、命令行参数
- 3创建容器ApplicationContext
- 4登记你的 Bean@ComponentScan 扫到的类、你的 @Configuration
- 5自动配置登场读清单、筛选、登记 Bean 图纸
- 6建内嵌 TomcatonRefresh()
- 7按图纸造 BeanDataSource、DispatcherServlet……
- 8开门营业监听端口,调用 ApplicationRunner
为什么你的 Bean 说了算
第 4 站先登记你的;第 5 站检查员才问“你自己装过没”。@ConditionalOnMissingBean 看到你的,就让位。
自动配置只画图纸
第 5 站只登记 BeanDefinition,真正 new 出来在第 7 站。所以条件判断发生在任何 Bean 被创建之前。
检查员的八个问题
清单卡片上最常见的条件注解。加粗的那个最重要:它让你能覆盖任何默认配置。
@ConditionalOnClass零件到了吗?classpath 里有这个类
@ConditionalOnMissingClassclasspath 里没有这个类
@ConditionalOnBean容器里已经有这种 Bean
@ConditionalOnMissingBean你自己没装过。装过就让位
@ConditionalOnProperty配置开关打开了吗
@ConditionalOnWebApplication这是 Web 应用吗
@ConditionalOnSingleCandidate这种 Bean 只有一个,或者有一个 @Primary
@ConditionalOnResource某个资源文件存在吗
想改默认配置,从轻到重四种做法
能用轻的就别用重的。越往右,你要自己负责的东西越多。
application.yml 里写 server.port: 9090、spring.datasource.url。最常用。
写一个 Customizer,比如 WebMvcConfigurer、Jackson2ObjectMapperBuilderCustomizer,在默认基础上改。
写自己的 @Bean。带 @ConditionalOnMissingBean 的默认 Bean 会让位。
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
============================
CONDITIONS EVALUATION REPORT
============================
Positive matches: ← 装上的
-----------------
DataSourceAutoConfiguration matched:
- @ConditionalOnClass found required classes 'javax.sql.DataSource',
'org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType' (OnClassCondition)
Negative matches: ← 跳过的,并写明哪个条件没过
-----------------
RedisAutoConfiguration:
Did not match:
- @ConditionalOnClass did not find required class
'org.springframework.data.redis.core.RedisOperations' (OnClassCondition)
Exclusions: ← 被你 exclude 的
-----------
None
自己做一个礼包
公司内部的通用组件,做成 starter,别的项目加一行依赖就能用。命名习惯:官方叫 spring-boot-starter-xxx,第三方叫 xxx-spring-boot-starter(比如 mybatis-spring-boot-starter)。
hello-spring-boot-starter礼包:只有一个 pom,没有代码hello-spring-boot-autoconfigure清单卡片 + 登记文件hello-core真正的功能代码@AutoConfiguration // 一张清单卡片@Configuration(proxyBeanMethods = false) // Boot 2.7 以前没有 @AutoConfiguration
@ConditionalOnClass(HelloService.class) // 零件在才装
@EnableConfigurationProperties(HelloProperties.class)
public class HelloAutoConfiguration {
@Bean
@ConditionalOnMissingBean // 用户自己装了就让位
@ConditionalOnProperty(prefix = "hello", name = "enabled", matchIfMissing = true)
public HelloService helloService(HelloProperties props) {
return new HelloService(props.getGreeting());
}
}
@ConfigurationProperties(prefix = "hello") // 读 application.yml 里的 hello.*
public class HelloProperties {
private String greeting = "你好";
// getter / setter
}
src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.importscom.acme.hello.HelloAutoConfiguration
src/main/resources/META-INF/spring.factoriesorg.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.acme.hello.HelloAutoConfiguration
JDK 8 和 JDK 17:清单换了个地方放
JDK 8 对应 Boot 2,JDK 17 对应 Boot 3。礼包、清单、检查员三个角色都还在。
Spring Boot 2.x
JDK 8+- 清单写在
META-INF/spring.factories,键是EnableAutoConfiguration - 卡片就是普通
@Configuration,先后靠@AutoConfigureAfter - 2.7 起新增
.imports文件和@AutoConfiguration,两种写法都认 - 条件里的 Web 类名是
javax.servlet.*
Spring Boot 3.x
JDK 17+- 只认
META-INF/spring/…AutoConfiguration.imports;登记在spring.factories里的自动配置不再加载 - 一个
@AutoConfiguration(after = …)同时管“我是卡片”和先后顺序 - Web 类名换成
jakarta.servlet.*。还写 javax 的老卡片,@ConditionalOnClass找不到类,静默跳过 - 打 GraalVM 原生镜像时,条件在构建期就判定好,运行时不再变
javax.sql.DataSource 在 Boot 3 里也没改名:它属于 JDK 本身,不归 Jakarta EE 管。
常踩的坑
大多数“为什么没生效”,打开验收单就能找到原因。
清单还登记在 spring.factories。挪到 AutoConfiguration.imports 文件。
它只看“此刻已经登记”的 Bean,结果取决于顺序。官方建议只在自动配置类里用。
它被当成你的 Bean 提前登记,失去“最后再看你装没装”的位置。放在扫描不到的包里,只靠清单加载。
启动报 Failed to configure a DataSource。配上 spring.datasource.url,或 exclude DataSourceAutoConfiguration。
默认的 SecurityFilterChain 生效了:所有接口都要登录。写一个自己的 SecurityFilterChain。
这张卡片按名字判断:@ConditionalOnMissingBean(name = "redisTemplate")。你的 Bean 换了名字,它照样再建一个。
WebMvcAutoConfiguration 整张卡片让位。只想加配置,实现 WebMvcConfigurer 就够了。
写 debug: true 看验收单,或访问 /actuator/conditions。