百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程字典 > 正文

SpEL表达式语言学习介绍

toyiye 2024-06-21 12:27 9 浏览 0 评论

简介

SpEL是Spring Expression Language(spring表达式语言)的缩写。它是一款强大的,为spring平台全线产品实现的一个通用表达式语言框架。但它不强依赖spring平台,也可以单独使用。只是基于spring使用起来更便捷。本文是学习总结,对这方面感兴趣的提供参考。

示例

SpEL依赖包为spring-expression-{version}.jar,在项目使用中添加对应依赖。

函数

学习先从hello world开始。

@Test
public void testSpEL(){
 ExpressionParser parser = new SpelExpressionParser();
 Expression exp = parser.parseExpression("'Hello World'.concat('!')");
 String message = (String) exp.getValue();
 System.out.println(message);
}
打印结果为:Hello World!

以上例子,可得出SpEL的使用范式。

1. 通过SpelExpressionParser类实例化一个ExpressionParser接口对象。

2. 使用ExpressionParser对象的parseExpression方法解析输入的表达式。

3. 调用Expression对象的getValue方法获取最终结果。

例子中的输入参数包含两个字符串'Hello World'和'!',并使用了一个concat字符串函数。最终getValue将把concat函数的应用结果(两个字符串的拼接)返回出来。

看上去so easy!3步即可完成一次表达式的完整解析。整个世界瞬间美丽了许多,我们只关心结果,过程就交给框架吧!

对象属性

表达式中不仅支持函数调用,还支持对象的属性获取。

ExpressionParser parser = new SpelExpressionParser();
// invokes 'getBytes()'
Expression exp = parser.parseExpression("'Hello World'.bytes");
byte[] bytes = (byte[]) exp.getValue();

上例中,bytes是字符串'Hello World'字符串对象的一个属性字段,'Hello World'.bytes,等价于'Hello World'.getBytes()方法调用,属性方法需满足java pojo的规则要求。

也支持多级属性访问。

ExpressionParser parser = new SpelExpressionParser();
// invokes 'getBytes().length'
Expression exp = parser.parseExpression("'Hello World'.bytes.length");
int length = (Integer) exp.getValue();

构造函数

构造器方法支持

ExpressionParser parser = new SpelExpressionParser();
Expression exp = parser.parseExpression("new String('hello world').toUpperCase()");
String message = exp.getValue(String.class);

上下文对象

上下文对象属性解析支持

// Create and set a calendar
GregorianCalendar c = new GregorianCalendar();
c.set(1856, 7, 9);
// The constructor arguments are name, birthday, and nationality.
Inventor tesla = new Inventor("Nikola Tesla", c.getTime(), "Serbian");
ExpressionParser parser = new SpelExpressionParser();
Expression exp = parser.parseExpression("name");
EvaluationContext context = new StandardEvaluationContext(tesla);
String name = (String) exp.getValue(context);

以上示例解析结果为Nikola Tesla。

也可以通过以下方式传递上下文对象

/ Create and set a calendar
GregorianCalendar c = new GregorianCalendar();
c.set(1856, 7, 9);
// The constructor arguments are name, birthday, and nationality.
Inventor tesla = new Inventor("Nikola Tesla", c.getTime(), "Serbian");
ExpressionParser parser = new SpelExpressionParser();
Expression exp = parser.parseExpression("name");
String name = (String) exp.getValue(tesla);

上面2个示例差别,getValue方法中参数一个是解析对象通过EvaluationContext封装,一个是直接传递解析对象。EvaluationContext一般是解析对象不太改变的情况,通过封装后内部会做一些缓存处理。如果解析对象经常变换,则推荐直接传递对象。

SpEL 编译模式

spel表达式默认是解释(interpreted)执行的,这种方式是在运行时一步一步动态解析。在某些特殊的场景,执行性能可能会比较差。为了应对这类场景,spel提供了表达式编译(compilation)执行方式。

编译模式当第一次解释(interpreted)执行表达式处理时,会生成一个java class。该类会用于执行后续对应的表达式处理。由于编译(compilation)方式缺乏表达式的数据类型,所以需要在第一次解释(interpreted)执行阶段收集相关类型。从这个过程可以看出,若spel表达式的数据类型是经常变化的,则不推荐采用编译(compilation)模式。

两种模式的性能对比:

someArray[0].someProperty.someOtherProperty < 0.1

通过以上表达式进行基准测试,循环50000对一个数组中一个属性对象子属性进行数字比较解释(interpreted)执行花75ms,编译(compilation)执行仅花3ms。可以看出两者有20多倍的性能差距。

SpEL 编译模式 - 配置

spel提供了一个org.springframework.expression.spel.SpelCompilerMode类,定义了对应的模式配置。

  • OFF - 默认模式,关闭编译模式
  • IMMEDIATE - 编译模式
  • MIXED - 编译和解释混合模式。优先以编译模式执行,当发现解析出现异常后自动切换为解释模式。

示例:

SpelParserConfiguration config = new SpelParserConfiguration(SpelCompilerMode.IMMEDIATE,
 this.getClass().getClassLoader());
SpelExpressionParser parser = new SpelExpressionParser(config);
Expression expr = parser.parseExpression("payload");
MyMessage message = new MyMessage();
Object payload = expr.getValue(message);
说明:通过SpelParserConfiguration配置类加载对应解析模式。

SpEL bean定义支持

SpEL表达式支持Bean定义。可以应用于xml和代码注解中。引用格式:

#{ <expression string> }

xml的bean定义支持

<bean id="numberGuess" class="org.spring.samples.NumberGuess">
 <property name="randomNumber" value="#{ T(java.lang.Math).random() * 100.0 }"/>
 <!-- other properties -->
</bean>
<bean id="taxCalculator" class="org.spring.samples.TaxCalculator">
 <property name="defaultLocale" value="#{ systemProperties['user.region'] }"/>
 <!-- other properties -->
</bean>
说明:systemProperties是spel框架预置变量。
<bean id="numberGuess" class="org.spring.samples.NumberGuess">
 <property name="randomNumber" value="#{ T(java.lang.Math).random() * 100.0 }"/>
 <!-- other properties -->
</bean>
<bean id="shapeGuess" class="org.spring.samples.ShapeGuess">
 <property name="initialShapeSeed" value="#{ numberGuess.randomNumber }"/>
 <!-- other properties -->
</bean>

注解bean定义支持

public static class FieldValueTestBean
 @Value("#{ systemProperties['user.region'] }")
 private String defaultLocale;
 public void setDefaultLocale(String defaultLocale) {
 this.defaultLocale = defaultLocale;
 }
 public String getDefaultLocale() {
 return this.defaultLocale;
 }
}

说明:@Value 支持spel表达式定义。

操作符支持

spel表达式支持等于、不等于、大于、小于等操作符。

// evaluates to true
boolean trueValue = parser.parseExpression("2 == 2").getValue(Boolean.class);
// evaluates to false
boolean falseValue = parser.parseExpression("2 < -5.0").getValue(Boolean.class);
// evaluates to true
boolean trueValue = parser.parseExpression("'black' < 'block'").getValue(Boolean.class);

处理以上标准的操作符外,还支持instanceof 和matches 操作符

// evaluates to false
boolean falseValue = parser.parseExpression(
 "'xyz' instanceof T(int)").getValue(Boolean.class);
// evaluates to true
boolean trueValue = parser.parseExpression(
 "'5.00' matches '\^-?\\d+(\\.\\d{2})?
").getValue(Boolean.class); //evaluates to false boolean falseValue = parser.parseExpression( "'5.0067' matches '\^-?\\d+(\\.\\d{2})?
").getValue(Boolean.class);

考虑到操作符在xml格式标签中的冲突问题,操作符可以以下方式替换lt (<), gt (>), le (?), ge (>=), eq (==), ne (!=), div (/), mod (%), not (!)

type支持

spel通过T()操作符支持class的type说明。静态方法调用可以用该操作符。

Class dateClass = parser.parseExpression("T(java.util.Date)").getValue(Class.class);
Class stringClass = parser.parseExpression("T(String)").getValue(Class.class);
boolean trueValue = parser.parseExpression(
 " T(java.lang.Math).random() * 100.0 ")
 .getValue(Boolean.class);

变量支持

Inventor tesla = new Inventor("Nikola Tesla", "Serbian");
StandardEvaluationContext context = new StandardEvaluationContext(tesla);
context.setVariable("newName", "Mike Tesla");
parser.parseExpression("Name = #newName").getValue(context);
System.out.println(tesla.getName()) // "Mike Tesla"

说明:context.setVariable("newName", "Mike Tesla");上下文对象的setVariable

方法可以设置表达式变量。变量引用通过操作符#variableName定义。

方法支持

spel表达式支持自定义方法。自定义方法生效,通过StandardEvaluationContext 的registerFunction方法注册。

public void registerFunction(String name, Method m)

如,定义一个反转方法。

public abstract class StringUtils {
 public static String reverseString(String input) {
 StringBuilder backwards = new StringBuilder();
 for (int i = 0; i < input.length(); i++)
 backwards.append(input.charAt(input.length() - 1 - i));
 }
 return backwards.toString();
 }
}

将以上方法添加上下文并使用。

ExpressionParser parser = new SpelExpressionParser();
StandardEvaluationContext context = new StandardEvaluationContext();
context.registerFunction("reverseString",
 StringUtils.class.getDeclaredMethod("reverseString", new Class[] { String.class }));
String helloWorldReversed = parser.parseExpression(
 "#reverseString('hello')").getValue(context, String.class);

三元操作符支持

String falseString = parser.parseExpression(
 "false ? 'trueExp' : 'falseExp'").getValue(String.class);

相关推荐

为何越来越多的编程语言使用JSON(为什么编程)

JSON是JavascriptObjectNotation的缩写,意思是Javascript对象表示法,是一种易于人类阅读和对编程友好的文本数据传递方法,是JavaScript语言规范定义的一个子...

何时在数据库中使用 JSON(数据库用json格式存储)

在本文中,您将了解何时应考虑将JSON数据类型添加到表中以及何时应避免使用它们。每天?分享?最新?软件?开发?,Devops,敏捷?,测试?以及?项目?管理?最新?,最热门?的?文章?,每天?花?...

MySQL 从零开始:05 数据类型(mysql数据类型有哪些,并举例)

前面的讲解中已经接触到了表的创建,表的创建是对字段的声明,比如:上述语句声明了字段的名称、类型、所占空间、默认值和是否可以为空等信息。其中的int、varchar、char和decimal都...

JSON对象花样进阶(json格式对象)

一、引言在现代Web开发中,JSON(JavaScriptObjectNotation)已经成为数据交换的标准格式。无论是从前端向后端发送数据,还是从后端接收数据,JSON都是不可或缺的一部分。...

深入理解 JSON 和 Form-data(json和formdata提交区别)

在讨论现代网络开发与API设计的语境下,理解客户端和服务器间如何有效且可靠地交换数据变得尤为关键。这里,特别值得关注的是两种主流数据格式:...

JSON 语法(json 语法 priority)

JSON语法是JavaScript语法的子集。JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔花括号保存对象方括号保存数组JS...

JSON语法详解(json的语法规则)

JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔大括号保存对象中括号保存数组注意:json的key是字符串,且必须是双引号,不能是单引号...

MySQL JSON数据类型操作(mysql的json)

概述mysql自5.7.8版本开始,就支持了json结构的数据存储和查询,这表明了mysql也在不断的学习和增加nosql数据库的有点。但mysql毕竟是关系型数据库,在处理json这种非结构化的数据...

JSON的数据模式(json数据格式示例)

像XML模式一样,JSON数据格式也有Schema,这是一个基于JSON格式的规范。JSON模式也以JSON格式编写。它用于验证JSON数据。JSON模式示例以下代码显示了基本的JSON模式。{"...

前端学习——JSON格式详解(后端json格式)

JSON(JavaScriptObjectNotation)是一种轻量级的数据交换格式。易于人阅读和编写。同时也易于机器解析和生成。它基于JavaScriptProgrammingLa...

什么是 JSON:详解 JSON 及其优势(什么叫json)

现在程序员还有谁不知道JSON吗?无论对于前端还是后端,JSON都是一种常见的数据格式。那么JSON到底是什么呢?JSON的定义...

PostgreSQL JSON 类型:处理结构化数据

PostgreSQL提供JSON类型,以存储结构化数据。JSON是一种开放的数据格式,可用于存储各种类型的值。什么是JSON类型?JSON类型表示JSON(JavaScriptO...

JavaScript:JSON、三种包装类(javascript 包)

JOSN:我们希望可以将一个对象在不同的语言中进行传递,以达到通信的目的,最佳方式就是将一个对象转换为字符串的形式JSON(JavaScriptObjectNotation)-JS的对象表示法...

Python数据分析 只要1分钟 教你玩转JSON 全程干货

Json简介:Json,全名JavaScriptObjectNotation,JSON(JavaScriptObjectNotation(记号、标记))是一种轻量级的数据交换格式。它基于J...

比较一下JSON与XML两种数据格式?(json和xml哪个好)

JSON(JavaScriptObjectNotation)和XML(eXtensibleMarkupLanguage)是在日常开发中比较常用的两种数据格式,它们主要的作用就是用来进行数据的传...

取消回复欢迎 发表评论:

请填写验证码