Spring Framework - SpEL详解

文章介绍了SpringExpressionLanguage(SpEL)的强大特性,如支持方法调用和字符串模板,以及EvaluationContext在解析和操作对象图中的作用,包括Simple和StandardEvaluationContext的区别。
摘要由CSDN通过智能技术生成

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;
	}

如果有问题欢迎评论指正!多谢

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值