由于问题特别提到了 SpEL(我在使用 SpEL 时也发现了这个问题),在不使用 Method 引用的情况下将自定义函数添加到评估上下文的另一种方法是添加自定义 MethodResolver (@ 987654321@, GitHub) 到StandardEvaluationContext。这种方法的一个好处是可以使用它向评估上下文中添加静态和非静态方法,而使用registerFunction 方法只能添加静态方法。
将自定义MethodResolver 添加到StandardEvaluationContext 的代码相当简单。下面是一个可执行示例,展示了如何执行此操作:
public static void main(String[] args) throws Exception {
Function<String, String> sayHello = name -> "Hello, " + name;
// The evaluation context must have a root object, which can be set in the StandardEvaluationContext
// constructor or in the getValue method of the Expression class. Without a root object, the custom
// MethodResolver will not be called to resolve the function.
Object rootObject = new Object();
StandardEvaluationContext standardEvaluationContext = new StandardEvaluationContext(rootObject);
// Add the custom MethodResolver to the evaluation context that will return a MethodExecutor that
// Spring can use to execute the sayHello function when an expression contains "sayHello('<any string>')".
standardEvaluationContext.addMethodResolver((context, targetObject, methodName, argumentTypes) -> {
MethodExecutor methodExecutor = null;
if (methodName.equals("sayHello")
&& argumentTypes.size() == 1
&& String.class.isAssignableFrom(argumentTypes.get(0).getObjectType())
) {
methodExecutor = (innerContext, target, arguments) -> {
final String name = arguments[0].toString();
return new TypedValue(sayHello.apply(name));
};
}
return methodExecutor;
});
// Create an expression parser, parser the expression, and get the evaluated value of the expression.
SpelExpressionParser expressionParser = new SpelExpressionParser();
Expression expression = expressionParser.parseExpression("sayHello('World!')");
String expressionValue = expression.getValue(standardEvaluationContext, String.class);
// Output the expression value, "Hello, World!", to the console.
System.out.println(expressionValue);
}
执行上述代码输出到控制台的表达式的值为:
Hello, World!
请注意,当使用MethodResolver 将函数添加到评估上下文时,函数不应在表达式字符串中以# 为前缀。这是使用MethodResolver 和使用registerFunction 方法将函数添加到评估上下文之间的主要区别。
sayHello('World!') // will work!
#sayHello('World!') // will not work!
如果您正在考虑将现有解决方案从使用 registerFunction 方法迁移到使用 MethodResolver 方法,请记住这一点。