新闻详情

新闻详情

首页 / 资讯中心 / 详情

Spring Boot 自动装配不是 @Configuration 的替代品:@Conditional 家族里 3 个容易误判的条件

发布时间:2026/10/1 15:33:37来源:尧图网络
Spring Boot 自动装配不是 @Configuration 的替代品:@Conditional 家族里 3 个容易误判的条件
title: Spring Boot 自动装配不是 Configuration 的替代品Conditional 家族里 3 个容易误判的条件date: 2026-09-25tags: [Spring Boot, 自动装配, Conditional, 源码, Java]2024 年做微服务基础组件升级我们写了一个自定义 starter 给全团队用。starter 里配了一个RestTemplateCustomizer用来统一加 traceId 请求头。本地测试没问题但一上线就发现有的服务生效了有的服务没生效。排查了半天发现是ConditionalOnClass写错了类名有的服务 classpath 里有那个类有的没有。这篇文章把 Spring Boot 自动装配的加载流程和Conditional的判定逻辑拆开聊清楚OnClass、OnMissingBean、OnProperty到底怎么判断以及我踩过的 3 个坑。一、事故现场同一个 starter有的服务生效有的不生效starter 的核心配置类Configuration ConditionalOnClass(name org.springframework.web.client.RestTemplate) public class TraceRestTemplateAutoConfiguration { Bean ConditionalOnMissingBean public RestTemplateCustomizer traceRestTemplateCustomizer() { return restTemplate - restTemplate.getInterceptors().add(new TraceIdInterceptor()); } } class TraceIdInterceptor implements ClientHttpRequestInterceptor { Override public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException { request.getHeaders().add(X-Trace-Id, MDC.get(traceId)); return execution.execute(request, body); } }问题出在ConditionalOnClass(name ...RestTemplate)。本地 Spring Boot 服务都有RestTemplate但有一个纯消息消费服务没有 web 依赖classpath 里没有RestTemplate所以这个配置类根本没加载。二、自动装配的加载流程Spring Boot 启动时会读取META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.importsSpring Boot 2.7或META-INF/spring.factories旧版com.example.starter.TraceRestTemplateAutoConfigurationSpringFactoriesLoader会加载这些类然后交给 Spring 容器处理。注意加载的是类名不是 bean 实例。真正决定是否实例化为 bean要看上面的Conditional注解是否满足。AutoConfiguration.imports里的类会被解析为候选配置类然后逐个计算Conditional条件。条件不满足的类会被跳过不会注册任何 bean。三、ConditionalOnClass 的判定逻辑ConditionalOnClass对应的实现是OnClassConditionOrder(Ordered.HIGHEST_PRECEDENCE) class OnClassCondition extends FilteringSpringBootCondition { Override protected ConditionOutcome[] getOutcomes(String[] autoConfigurationClasses, AutoConfigurationMetadata autoConfigurationMetadata) { // 使用 ASM 读取配置类上的 ConditionalOnClass 注解 // 检查 classpath 中是否存在指定类 } }ConditionalOnClass可以用两种写法ConditionalOnClass(RestTemplate.class) public class XxxConfiguration { } ConditionalOnClass(name com.example.SomeClass) public class XxxConfiguration { }第一种写法RestTemplate.class会直接引用类。如果 classpath 里没有RestTemplate编译时就会报错。第二种写法用字符串可以在运行时判断避免编译期依赖。对于 starter 这种可能被不同服务引用的场景应该用name ...字符串形式。四、ConditionalOnMissingBean 的坑顺序问题ConditionalOnMissingBean判断容器中是否缺少指定类型的 bean。但它只在当前配置类被解析时判断。如果用户自定义的 bean 在更后面才加载starter 里的 bean 可能已经先创建了。Configuration public class MyAutoConfig { Bean ConditionalOnMissingBean public UserService userService() { return new DefaultUserService(); } }如果用户的配置类UserConfig在MyAutoConfig之后加载那userService()会创建一个DefaultUserService而不是用户自定义的。解决方法是让自动配置类在用户配置之后处理或者明确指定用户 bean 的加载顺序。五、ConditionalOnProperty 的坑默认值和 matchIfMissingConditionalOnProperty(prefix trace, name enabled, havingValue true)这个条件要求trace.enabledtrue才加载。如果没有配置trace.enabled默认是 false配置类不加载。如果想默认开启ConditionalOnProperty(prefix trace, name enabled, havingValue true, matchIfMissing true)matchIfMissing true表示如果没有配置也视为匹配。这个参数很多 starter 都在用但要谨慎否则默认行为可能出乎意料。六、源码条件判断发生在配置类解析阶段ConfigurationClassParser在解析配置类时会调用ConditionEvaluatorclass ConditionEvaluator { public boolean shouldSkip(AnnotatedTypeMetadata metadata, ConfigurationPhase phase) { if (metadata null || !metadata.isAnnotated(Conditional.class.getName())) { return false; } ListCondition conditions new ArrayList(); for (String[] conditionClasses : getConditionClasses(metadata)) { for (String conditionClass : conditionClasses) { Condition condition getCondition(conditionClass, this.context.getClassLoader()); conditions.add(condition); } } for (Condition condition : conditions) { ConfigurationPhase requiredPhase null; if (condition instanceof ConfigurationCondition) { requiredPhase ((ConfigurationCondition) condition).getConfigurationPhase(); } if ((requiredPhase null || requiredPhase phase) !condition.matches(this.context, metadata)) { return true; } } return false; } }如果某个Conditional的matches返回 false这个配置类就会被跳过。七、别靠猜--debug 的条件评估报告那次排查花了两小时其中大部分时间在猜哪个条件没过。后来才知道 Spring Boot 自带答案启动加--debug参数或debugtrue配置会打印完整的CONDITIONS EVALUATION REPORTTraceRestTemplateAutoConfiguration: Did not match: - ConditionalOnClass did not find required class org.springframework.web.client.RestTemplate (OnClassCondition) Exclusions: ----------- NoneDid not match区块会逐条列出每个自动配置类没生效的具体条件和原因括号里是对应的 Condition 实现类。如果当时直接看这个报告5 分钟就能定位到是 classpath 缺类而不是盯着代码怀疑逻辑写错了。还有一个源码级的细节值得知道自动配置类之间的顺序靠AutoConfigureBefore/AutoConfigureAfter控制而不是 Spring 的Order。这两个注解只在AutoConfiguration.imports里声明的类之间生效写在普通用户配置类上没有任何效果——我们团队就有同事在业务配置类上加了AutoConfigureAfter然后疑惑为什么不起作用。AutoConfiguration AutoConfigureBefore(DataSourceAutoConfiguration.class) ConditionalOnClass(DataSource.class) public class MyDataSourceDecoratorAutoConfiguration { // 保证在默认数据源装配之前介入 }八、我的取舍判断写 starter 时ConditionalOnClass尽量用字符串形式避免编译期依赖。ConditionalOnMissingBean要考虑自动配置和用户配置的加载顺序。ConditionalOnProperty的默认值要明确慎用matchIfMissing true。不要滥用自动装配。核心业务 bean 最好让用户显式配置不要偷偷自动注入。九、复盘真实数字受影响服务5 个中的 1 个排查时间2 小时修复把ConditionalOnClass(RestTemplate.class)改成name ...验证全团队服务重新发布5 个服务全部生效十、思考题你写过自定义 starter 吗有没有遇到过Conditional条件判断不符合预期的情况
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

Ubuntu 22.04 安装 Miniconda、PyTorch 与 YOLOv8 并完成 CPU 推理 2026/10/1 16:12:42

Ubuntu 22.04 安装 Miniconda、PyTorch 与 YOLOv8 并完成 CPU 推理

Ubuntu 22.04 安装 Miniconda、PyTorch 与 YOLOv8 并完成 CPU 推理本文记录在 VMware Ubuntu 22.04 虚拟机中安装 Miniconda、PyTorch CPU 版和 Ultralytics YOLOv8,并使用 YOLOv8n 对示例图片进行目标检测的完整过程。一、实验环境项目配置操作系统Ubuntu 22.04.5 …

阅读更多 →
9.30blog 2026/10/1 16:12:42

9.30blog

2026年9月24日 14:09 1.printf 占位符的作用是用“”后面的数据或词句替换语句中的占位符(指定格式) 例如:printf(“There are %d apples”,2); 生成There are 2 apples 例2printf(“%s will come tonight\n”,“张三”); 例3printf(“%s say…

阅读更多 →
带父母孩子去阳澄湖吃蟹,湖景包厢到底适不适合一家人坐进去 2026/10/1 16:12:42

带父母孩子去阳澄湖吃蟹,湖景包厢到底适不适合一家人坐进去

先说结论:适合,但前提是你对“湖景包厢”的期待不是一块招牌,而是老人孩子坐下来之后真实的体验。带家人出门吃饭,最容易出问题的往往不是菜好不好吃,而是环境名不副实、桌子挤、上菜慢,老人孩子都别扭。我…

阅读更多 →
(146页PPT)某大型企业基于战略的全面绩效管理体系设计方案(附下载方式) 2026/10/1 16:12:42

(146页PPT)某大型企业基于战略的全面绩效管理体系设计方案(附下载方式)

篇幅所限,本文只提供部分资料内容,完整资料请看下面链接 (146页PPT)某大型企业基于战略的全面绩效管理体系设计方案.pptx_基于物联网的消防监控方案资源-CSDN下载 资料解读:《(146页PPT)某大型…

阅读更多 →
Designer Skills五大集合全景图:33个插件覆盖研究到交付,找到最适合你的安装路径 2026/10/1 16:12:42

Designer Skills五大集合全景图:33个插件覆盖研究到交付,找到最适合你的安装路径

Designer Skills五大集合全景图:33个插件覆盖研究到交付,找到最适合你的安装路径 【免费下载链接】designer-skills Designer Skills Collection: agentic skills, commands, and plugins for design — from research to systems, UI, interaction, and…

阅读更多 →
Unity热更新安全加固:从AssetBundle清单签名到本地缓存防篡改 2026/10/1 16:12:35

Unity热更新安全加固:从AssetBundle清单签名到本地缓存防篡改

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉