@ConditionalOnExpression是唯一原生支持SpEL的Spring Boot条件注解,通过SpelExpressionParser解析表达式并依赖StandardEvaluationContext访问environment等上下文对象;其他条件注解如@ConditionalOnProperty不支持SpEL,强行使用将导致运行时解析失败或条件不匹配。

Spring Boot条件注解中只有@ConditionalOnExpression明确支持SpEL表达式,其他如@ConditionalOnProperty、@ConditionalOnClass等均不接受SpEL语法,强行写入会导致编译通过但运行时解析失败或条件始终不匹配。
@ConditionalOnExpression是唯一原生支持SpEL的条件注解
该注解直接将字符串值传入SpEL解析器,由OnExpressionCondition类调用SpelExpressionParser执行求值,最终返回Boolean结果决定Bean是否注册。
它被设计为@Conditional的扩展实现,底层依赖StandardEvaluationContext,并自动注入BeanFactoryResolver,因此可在表达式中访问environment、systemProperties等上下文对象。
SpEL在@ConditionalOnExpression中的合法写法
方法一:直接比较配置项字符串值
@ConditionalOnExpression("#{'${app.mode}'.equals('prod')}")
注意:必须用单引号包裹${...}占位符,否则SpEL会把未加引号的${app.mode}当作变量名而非字符串字面量解析,导致NoSuchBeanDefinitionException。
方法二:组合多个配置判断
@ConditionalOnExpression("#{'${cache.type}'.equals('redis') and '${cache.enabled}'.equals('true')}")
方法三:调用环境对象方法获取配置
将 Spring Boot 2.7 项目升级到 Spring Boot 3.5 的实战流程,覆盖版本基线、依赖坐标替换、Jakarta 迁移、配置兼容、异步上下文传递改造与验证门禁。用于企业多模块 Maven 项目升级与排障。
@ConditionalOnExpression("#{environment.getProperty('feature.flag', 'false').equals('true')}")
这一步操作起来很简单,直接把environment.getProperty()写进表达式就行,但要注意默认值必须用单引号包裹,否则'false'会被当成布尔字面量,而字符串'false'.equals('true')恒为false。
错误用法示例(务必避开)
① 在@ConditionalOnProperty中使用SpEL
@ConditionalOnProperty(name = "#{environment['app.env']}", havingValue = "dev") → 【编译无报错,但运行时name字段不支持SpEL,会被当作字面量字符串#{environment['app.env']}处理】
② 忘记为占位符加引号
@ConditionalOnExpression("${app.debug} == true") → SpEL尝试解析变量${app.debug},若该配置未定义,则抛出SpelEvaluationException: EL1008E: Property or field 'true' cannot be found on object
③ 混淆@Value与@ConditionalOnExpression的语法边界
@ConditionalOnExpression("@value('${app.timeout}') > 1000") → 【@Value不能在SpEL表达式里嵌套调用,且@ConditionalOnExpression不识别@Value注解】

















