如何禁用SpEL的短路求值?应用表达式校验场景技术求助
解决SpEL禁用短路求值的方案
要在SpEL中禁用短路求值(让&&/||这类逻辑运算符强制执行所有操作数,不管前面的结果),核心思路是通过**自定义运算符重载器(OperatorOverloader)**来接管逻辑运算符的处理逻辑,确保左右两个操作数都会被求值。
具体实现步骤
1. 自定义非短路运算符重载器
创建一个实现OperatorOverloader接口的类,专门处理AND和OR运算符,强制先执行左右两个操作数的求值,再返回逻辑结果:
import org.springframework.expression.OperatorOverloader; import org.springframework.expression.EvaluationContext; import org.springframework.expression.Operator; public class NonShortCircuitOperatorOverloader implements OperatorOverloader { @Override public boolean supportsOperation(Operator operator, Object leftOperand, Object rightOperand) { // 只接管逻辑与(&&)和逻辑或(||)的处理 return operator == Operator.AND || operator == Operator.OR; } @Override public Object operate(Operator operator, Object leftOperand, Object rightOperand, EvaluationContext context) { // 注意:到这一步时,SpEL已经完成了左右操作数的求值 // 因为我们重载了运算符,SpEL会先执行两边的表达式,再调用这个方法 Boolean leftVal = (Boolean) leftOperand; Boolean rightVal = (Boolean) rightOperand; if (operator == Operator.AND) { return leftVal && rightVal; } else if (operator == Operator.OR) { return leftVal || rightVal; } return null; // 其他运算符无需处理 } }
2. 将重载器绑定到EvaluationContext
在你初始化EvaluationContext(比如StandardEvaluationContext)的时候,把自定义的重载器设置进去:
// 假设你的根对象是yourAppRootObject StandardEvaluationContext evalContext = new StandardEvaluationContext(yourAppRootObject); // 注册非短路运算符重载器 evalContext.setOperatorOverloader(new NonShortCircuitOperatorOverloader());
为什么这个方案有效?
SpEL默认的短路逻辑是:遇到&&时先算左边,若为false则直接返回false,跳过右边求值;遇到||时左边为true则直接返回true。而当你注册了自定义OperatorOverloader后,SpEL会先完成左右两个操作数的全部求值,再调用你重载的operate方法计算最终结果——这样就彻底禁用了短路,所有表达式部分都会被执行,正好满足你校验表达式一致性的需求:任何一个方法调用或表达式片段抛出异常,都会被你捕获并标记表达式无效。
额外注意事项
- 确保你使用的是
StandardEvaluationContext(或支持OperatorOverloader的Context实现),简化版的SimpleEvaluationContext不支持运算符重载。 - 这个方案只会影响
&&和||运算符,单目运算符!不存在短路问题,无需额外处理。 - 测试时可以用类似
false && throwExceptionMethod()的表达式验证:正常短路情况下不会执行throwExceptionMethod,但用了自定义重载器后会执行该方法并抛出异常,说明短路已被禁用。
内容的提问来源于stack exchange,提问作者tkralik
相关产品推荐
相关产品推荐

