Spring表达式语言(简称
“SpEL”)是一种强大的表达式语言,支持在运行时查询和操作对象图。该语言的语法与统一EL相
似,但提供了额外的功能,最显著的是方法调用和基本的字符串模板功能。
虽然他是与Spring一家的,但他不光能服务于Spring,在需要用到它的任何地方,都能使用。
第一部分.
以下是一个最基本Spring提供的解析Spel表达式的API的使用
SpelExpressionParser parser = new SpelExpressionParser();
Expression expression = parser.parseExpression("'hello world'");
Object value = expression.getValue();
// value值为字符串hello world
同时,除了支持普通字符串,还能支持布尔,整型,浮点型,长整型等
SpelExpressionParser parser = new SpelExpressionParser();
Expression expression = parser.parseExpression("1");
// 输出Integer
System.out.println(expression.getValue().getClass());
SpelExpressionParser parser = new SpelExpressionParser();
Expression expression = parser.parseExpression("1.1f");
// 输出Float
System.out.println(expression.getValue().getClass());
SpelExpressionParser parser = new SpelExpressionParser();
Expression expression = parser.parseExpression("1.1");
// 输出Double
System.out.println(expression.getValue().getClass());
SpelExpressionParser parser = new SpelExpressionParser();
Expression expression = parser.parseExpression("1000l");
// 输出Long
System.out.println(expression.getValue().getClass());
还能调用对应的方法,这里摘抄文档中的一段示例
ExpressionParser parser = new SpelExpressionParser();
Expression exp = parser.parseExpression(“‘Hello World’.concat(‘!’)”);
String message = (String) exp.getValue();
ExpressionParser parser = new SpelExpressionParser();
// invokes ‘getBytes()’
Expression exp = parser.parseExpression(“‘Hello World’.bytes”); ①
byte[] bytes = (byte[]) exp.getValue();
猜想:他是否是通过反射获取点号前面的数据的封装类型的后面的字段/方法来访问/调用。任意打开一个包装类型的源码,这里截取部分Integer的源码
public final class Integer extends Number implements Comparable<Integer> {
/**
* A constant holding the minimum value an {@code int} can
* have, -2<sup>31</sup>.
*/
@Native public static final int MIN_VALUE = 0x80000000;
// ............
public int hashCode() {
return Integer.hashCode(value);
}
}
以此编写代码
SpelExpressionParser parser = new SpelExpressionParser();
Expression expression1 = parser.parseExpression("1.MIN_VALUE");
System.out.println(expression1.getValue());
Expression expression2 = parser.parseExpression("1.hashCode()");
System.out.println(expression2.getValue());
这第一眼看起来感觉要报错,但是运行完成后发现准确无误完全符合预期
第二部分.
EvaluationContext使用
EvaluationContext
接口在评估表达式以解析属性、方法或字段时使用,并帮助执行类型转换。Spring提供了两种实
现。
• SimpleEvaluationContext:
暴露了SpEL语言的基本特征和配置选项的一个子集,适用于不需要SpEL语言语法的全部范
围,并且应该被有意义地限制的表达类别。例如,包括但不限于数据绑定表达式和基于属性
的过滤器。
• StandardEvaluationContext:
暴露了全套的SpEL语言功能和配置选项。你可以用它来指定一个默认的根对象,并配置每个被设计为只支持SpEL语言语法的一个子集。它排除了Java类型引用、构造函数和Bean引用。它还
要求你明确选择对表达式中的属性和方法的支持程度。默认情况下, create()
静态工厂方法只允许对属性进行读取访问。你也可以获得一个 builder
来配置所需的确切支持级别,目标是以下的一个或一些组合。
• 仅限自定义 PropertyAccessor(无反射)。
• 用于只读访问的数据绑定属性
• 读和写的数据绑定属性
这是什么意思呢?首先Simple相当于Standard的残血版。
他所说的帮助执行类型转换指什么呢,一路debug,来到PropertyOrFieldReference类的writeProperty方法中可以找到答案
private void writeProperty(
TypedValue contextObject, EvaluationContext evalContext, String name, @Nullable Object newValue)
throws EvaluationException {
PropertyAccessor accessorToUse = this.cachedWriteAccessor;
if (accessorToUse != null) {
if (evalContext.getPropertyAccessors().contains(accessorToUse)) {
accessorToUse.write(evalContext, contextObject.getValue(), name, newValue);
return;
}
this.cachedWriteAccessor = null;
}
List<PropertyAccessor> accessorsToTry =
getPropertyAccessorsToTry(contextObject.getValue(), evalContext.getPropertyAccessors());
for (PropertyAccessor accessor : accessorsToTry) {
if (accessor.canWrite(evalContext, contextObject.getValue(), name)) {
this.cachedWriteAccessor = accessor;
accessor.write(evalContext, contextObject.getValue(), name, newValue);
return;
}
}
}
这里截取了部分代码
大概逻辑:如果accessor能进行写入操作,就将其保存到cachedWriteAccessor属性中,在下次需要修改数据时,可以直接用缓存的accessor,而EvaluationContext的作用便是提供这些Write数据要用的accessor。
而在SpelExpression类中的getEvaluation的方法中可知,默认使用的StandardEvaluationContext
public EvaluationContext getEvaluationContext() {
if (this.evaluationContext == null) {
this.evaluationContext = new StandardEvaluationContext();
}
return this.evaluationContext;
}