spring boot自动配置需精准使用@conditional系列注解:@conditionalonclass检查类路径是否存在指定类,@conditionalonmissingbean判断容器中是否缺失同类型bean(默认仅查当前上下文,应设search=searchstrategy.all),@conditionalonproperty依赖配置文件中显式存在key(matchifmissing=false防误触发),三者常组合使用;多条件校验宜自定义condition实现统一判断与日志;加载顺序通过@autoconfigurebefore/after、imports文件行序及@order/@primary分层控制。

要让Spring Boot自动配置类只在特定环境、依赖或Bean存在时才生效,必须精准使用@Conditional系列注解,否则会导致Bean重复注册、启动失败或配置被意外跳过。
核心条件注解的适用场景与选择逻辑
先明确每个注解不可替代的触发时机:@ConditionalOnClass检查类路径是否存在某类(如DataSource),不是看是否引入了starter;@ConditionalOnMissingBean判断IoC容器里有没有已注册的同类型Bean,注意它默认只在当前ApplicationContext中搜索;@ConditionalOnProperty则严格依赖application.yml中是否显式设置了某个key,哪怕值为false也满足“存在”条件。
这三者常组合使用。例如DataSourceAutoConfiguration同时加了@ConditionalOnClass({DataSource.class, EmbeddedDatabaseType.class})和@ConditionalOnMissingBean(type = "io.r2dbc.spi.ConnectionFactory"),确保只有当JDBC驱动在类路径、且R2DBC连接工厂未注册时,才走嵌入式数据源初始化流程。
避免踩坑的四个关键实践
方法一:用@ConditionalOnMissingBean时,务必指定search = SearchStrategy.ALL
默认SearchStrategy.CURRENT只查当前上下文,若Bean由父上下文(如SpringBootTest的测试上下文)注入,则该条件会误判为“缺失”,导致重复创建Bean。加上search = SearchStrategy.ALL才能穿透父子容器层级校验。
方法二:@ConditionalOnClass不要写内部类或默认包下的类
SpringFactoriesLoader加载机制依赖ClassLoader.getResources()扫描路径,而内部类字节码文件名含$符号,某些打包方式(如fat jar中的嵌套jar)可能无法被正确识别。始终使用public、非匿名、位于标准包路径下的顶层类。
方法三:@ConditionalOnProperty必须配matchIfMissing = false
【matchIfMissing = false是硬性要求】 否则当配置文件里根本没写这个属性时,条件反而成立,极易引发生产环境误触发——比如custom.mail.enabled未配置,却自动启用了邮件发送功能。
方法四:多条件并存时,优先用@Condition组合而非堆砌多个@Conditional
当需要“类存在 + 属性为true + Bean不存在”三重校验时,直接叠加三个注解虽可行,但可读性差且调试困难。应自定义一个继承Condition的类,在matches()中统一判断,并抛出明确日志说明哪条不满足,便于线上问题定位。
实战排序:从高危到高频的加载顺序控制
第一步:用@AutoConfigureBefore/@AutoConfigureAfter声明依赖关系
比如你的MyRedisAutoConfiguration要早于CacheAutoConfiguration执行,否则缓存管理器可能提前初始化而未绑定你自定义的RedisTemplate。这是唯一能精确控制自动配置类加载顺序的机制。
第二步:在META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports中按行序排列类名
Spring Boot 2.7+弃用spring.factories后,imports文件成为新入口。文件内每行一个全限定类名,顺序即加载顺序。把基础设施类(如DataSourceAutoConfiguration)放在前面,业务增强类(如MyCustomizer)放后面。
第三步:对同一类的多个@Bean方法,用@Order或@Primary做细粒度控制
@Order仅影响List注入时的顺序,@Primary解决同类型Bean冲突。二者不改变自动配置类本身的加载时机,但决定最终哪个Bean胜出。











