Spring Boot中@ConditionalOn注解自定义参数化及SpEL函数问题
我正在为客户处理外部API的新版本适配工作。此前我们的@Component Bean额外使用了如下注解做条件判断:
@ConditionalOnProperty(name = SOME_PROPERTY_NAME, havingValue = "val1")
现在多数场景下我会创建新的Component,并设置条件havingValue = "val2",但有部分Bean无需改动,需要在两种场景下共用。搜索后找到一个可行方案:
@ConditionalOnExpression("'${some.property}' == 'val1' or '${some.property}' == 'val2'")
但我了解到可以注册自定义函数用于SpEL表达式,这样在条件更复杂时写法会更简洁。
想请教这种场景下的最佳方案是什么?
我最初尝试为@ConditionalOnProperty添加逻辑,查阅资料后转向使用@ConditionalOnExpression。随后尝试创建StandardEvaluationContext并注册自定义函数,最终参考示例实现了BeanFactoryPostProcessor,同时定义了如下接口:
public interface CustomSpelFunctions { static boolean isIntegrationEnabled(@Value("${some.property}") String mode) { return ... } }
但实际运行时,似乎Bean在我完成函数注册前就已经创建了,当使用@ConditionalOnExpression("#{isIntegrationEnabled()}")时,出现如下错误:
EL1004E: Method call: Method isIntegrationEnabled() cannot be found on type org.springframework.beans.factory.config.BeanExpressionContext
我哪里操作有误?是否可以在@ConditionalOnExpression中使用自定义函数?还是只能直接在表达式中编写条件逻辑?
注:我刚从非Spring技术栈转过来,对Spring Java不太熟悉,我们使用的是spring-boot-starter-parent 2.4.13、Java 11。
编辑1
尝试按照方案修改(因找不到BeanExpressionResolver的getEvaluationContext方法,改用IntegrationContextUtils.getEvaluationContext(beanFactory))时,出现错误:
EL1041E: After parsing a valid expression, there is still more data in the expression: 'lparen(()'
于是参考相关解决方案,给表达式添加额外单引号:
@ConditionalOnExpression("'@isIntegrationEnabled('${some.property}')'")
但又出现错误:
EL1041E: After parsing a valid expression, there is still more data in the expression: 'VALUE_READ_FROM_PROPERTIES'
我理解这是在评估isIntegrationEnabled的参数时出现了问题。
编辑2
我注意到,当不在注解中使用该表达式时,以下代码返回null:
public static BeanFactoryPostProcessor spelFunctionPostProcessor() { return (ConfigurableListableBeanFactory beanFactory) -> { // StandardEvaluationContext context = (StandardEvaluationContext) beanFactory.getBeanExpressionResolver() // .getEvaluationContext(beanFactory, null); StandardEvaluationContext context = IntegrationContextUtils.getEvaluationContext(beanFactory); // ... }; }
编辑3
我检查了Spring 3.4.1与Java 17的环境,发现BeanExpressionResolver同样没有getEvaluationContext方法。
内容的提问来源于stack exchange,提问作者Zeb

