springboot条件注解仅在启动时执行一次判断,不影响运行时性能,但轻微延长上下文初始化时间;其判断发生在configurationclassparser解析阶段,主要开销来自类路径i/o扫描和属性map查找。

SpringBoot条件注解本身在应用启动阶段执行一次判断,不参与运行时逻辑,因此对应用运行期性能无影响,但会轻微延长上下文初始化时间。
条件注解的判断时机与开销来源
所有条件注解(如@ConditionalOnClass、@ConditionalOnProperty)都在Spring容器刷新前的ConfigurationClassParser解析阶段触发,此时仅做元数据扫描和轻量级校验,不实例化Bean、不执行业务代码。
真正耗时的操作集中在类路径扫描和属性解析:@ConditionalOnClass需调用ClassUtils.isPresent(),该方法通过ClassLoader.getResourceAsStream()检查class文件是否存在——这是I/O操作,但只读取MANIFEST或字节码头,不加载类;@ConditionalOnProperty则直接从Environment中getRequiredProperty(),本质是Map查找,开销可忽略。
高频误判场景及优化手段
方法一:避免嵌套复杂表达式
@ConditionalOnExpression("${app.feature.a:true} && ${app.feature.b:false} && ${app.feature.c:#{systemProperties['os.name'].contains('Windows')}}") 这种写法会触发SpEL解析器全量计算,且每次启动都重复执行。应拆分为多个独立注解,或改用@ConditionalOnProperty组合。
方法二:慎用@ConditionalOnBean配合泛型参数
@ConditionalOnBean(type = "org.springframework.data.redis.core.RedisTemplate extends Object, ? extends Object>") 会导致Spring内部调用ResolvableType.forClassWithGenerics()生成泛型类型树,比原始类型判断多出3~5倍CPU时间。替换为@ConditionalOnBean(RedisTemplate.class)即可。
【关键前提】所有条件注解的评估结果会被ConditionEvaluator缓存,同一应用生命周期内不会重复计算——但测试环境下反复启动应用上下文时,每次都会重新评估。
实测对比数据(基于Spring Boot 3.3.2)
步骤一:基准测试环境配置
使用spring-boot-starter-web + 12个自定义自动配置类,每个类含3个条件注解,其中2个为@ConditionalOnClass,1个为@ConditionalOnProperty。
步骤二:禁用条件注解后测量启动耗时
移除全部@Conditional*注解并替换为硬编码@Bean,应用启动时间从1842ms降至1796ms,差值仅46ms,占比2.5%。
步骤三:注入1个@ConditionalOnExpression并启用debug日志
观察到ConditionEvaluationReport显示该表达式单次解析耗时0.8ms,而同类简单@ConditionalOnProperty平均0.03ms——前者开销是后者的26倍,但仍在微秒级量级。











