Spring Boot条件注解执行入口是ConditionEvaluator.shouldSkip(),委托给SpringBootCondition.matches();@ConditionalOnClass通过OnClassCondition.getMatchOutcome检查类是否存在,任一缺失即不匹配。

要分析SpringBoot条件注解的源码,必须从Condition接口的执行入口切入,而不是直接翻@ConditionalOnClass这类注解的声明——因为它们本身只是元注解,真正干活的是背后实现Condition接口的OnClassCondition等具体类。
定位Condition执行的统一入口
Spring Boot在ConfigurationClassPostProcessor处理配置类时,会调用ConfigurationClassBeanDefinitionReader#loadBeanDefinitions方法;该方法内部对每个@Bean或@Configuration类调用conditionEvaluator.shouldSkip()判断是否跳过注册。
【shouldSkip()是所有条件注解实际触发的唯一入口】
这个conditionEvaluator是ConditionEvaluator类型实例,其shouldSkip方法最终委托给SpringBootCondition#matches()执行——所有条件注解(@ConditionalOnClass、@ConditionalOnBean等)都继承自SpringBootCondition,因此共用这一套模板流程。
跟踪@ConditionalOnClass的匹配逻辑
方法一:从OnClassCondition#getMatchOutcome入手
① 获取注解属性:调用getAttributes(metadata, ConditionalOnClass.class),提取value[]和name[]两个数组;
② 构造待检查类名列表:把Class>[]转为全限定名字符串,与String[] name合并去重;
将 Spring Boot 2.7 项目升级到 Spring Boot 3.5 的实战流程,覆盖版本基线、依赖坐标替换、Jakarta 迁移、配置兼容、异步上下文传递改造与验证门禁。用于企业多模块 Maven 项目升级与排障。
③ 逐个检查类是否存在:遍历列表,调用ClassUtils.isPresent(className, context.getClassLoader());
这一步依赖ClassLoader.loadClass(),但做了异常吞并——类不存在时捕获ClassNotFoundException并返回false,不会中断流程;
④ 汇总结果:只要有一个类缺失,整个@ConditionalOnClass就判定为不匹配,返回ConditionOutcome.noMatch();全部存在才返回match。
验证条件注解是否生效的调试技巧
启动应用时添加JVM参数:-Dlogging.level.org.springframework.boot.autoconfigure=TRACE
日志中会出现形如“Condition XYZ on class ABC matched”或“did not match”的明细记录,每条都对应一次getMatchOutcome调用结果。
注意:日志只打印最终判定结果,不显示中间类加载细节;若需观察ClassUtils.isPresent的具体行为,需在该方法上打断点。
这一步操作起来很简单,直接在IDE中对ClassUtils.isPresent右键→Find Usages,然后在调用处下断点即可。

















