EvaluationContext 接口在评估表达式以解决属性、方法或字段时使用,并帮助执行类型转换。Spring 提供了两种实现:
- SimpleEvaluationContext:暴露了 SpEL 语言的基本特征和配置选项的一个子集,适用于不需要SpEL 语言语法的全部范围并应受到有意义的限制的表达类别。例如,包括但不限于数据绑定表达式和基于属性的过滤器。
- StandardEvaluationContext:暴露了全套的 SpEL 语言特性和配置选项。你可以用它来指定一个默认的根对象,并配置每个可用的评估相关策略。
SimpleEvaluationContext 被设计为只支持 SpEL 语言语法的一个子集。它排除了 Java 类型引用、构造函数和 Bean 引用。它还要求你明确选择对表达式中的属性和方法的支持程度。默认情况下,create()
静态工厂方法只允许对属性进行读取访问。你也可以获得一个构建器来配置所需的确切支持级别,目标是以下的一个或一些组合:
- 仅限自定义 PropertyAccessor(无反射)。
- 用于只读访问的数据绑定属性
- 读和写的数据绑定属性
类型转换
默认情况下,SpEL 使用 Spring 核心中提供的转换服务(org.springframework.core.convert.ConversionService
)。这个转换服务为常见的转换提供了许多内置的转换器,但也是完全可扩展的,因此你可以添加类型之间的自定义转换。此外,它是泛型感知的。这意味着,当你在表达式中使用通用类型时, SpEL 会尝试进行转换以保持它所遇到的任何对象的类型正确性。
这在实践中是什么意思?假设赋值,使用 setValue()
,被用来设置一个 List 属性。该属性的类型实际上是 List<Boolean>
。SpEL 认识到,列表中的元素在被放入之前需要被转换为布尔值。下面的例子显示了如何做到这一点:
package cn.mrcode.study.springdocsread.data;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.SimpleEvaluationContext;
import java.util.ArrayList;
import java.util.List;
/**
* @author mrcode
*/
public class DemoTest {
public static void main(String[] args) {
ExpressionParser parser = new SpelExpressionParser();
Simple simple = new Simple();
simple.booleanList.add(true);
// 创建一个只读的数据绑定
EvaluationContext context = SimpleEvaluationContext
.forReadOnlyDataBinding()
.build();
// "false" 在这里是作为一个字符串传入的。
// SpEL 和转换服务会认识到它需要是一个布尔值并进行相应的转换。
parser.parseExpression("booleanList[0]").setValue(context, simple, "false");
// 上面声明的是只读,但是上面这一条语句却做了写操作,而且也能写入,是不是很迷惑?
// 你要注意的是:对于 list 这种引用类型来讲,是对 list 的写,而不是对 simple.booleanList 这个字段的写
// 比如下面这一行:就是对 simple.booleanList 的写,就会报错了
// parser.parseExpression("booleanList").setValue(context, simple, new ArrayList<>());
// b = false
Boolean b = simple.booleanList.get(0);
System.out.println(b);
}
static class Simple {
// 需要注意的是这个 方法权限,如果是 private 就会报错
// 是 private 的话,如果你提供了 getter 方法 也算是公开方法
public List<Boolean> booleanList = new ArrayList<Boolean>();
}
}