SpEL基本操作–Week12企业级开源框架课程内容

SpEL基本操作–Week12企业级开源框架课程内容1 创建表达解析器 2 创建环境变量类 3 创建一个 任意类型的 变量 4 给变量环境 ctx 增加变量 list 值为 list 刚才定义的数组 5 6 通过表达式去读写环境变量的值 1

大家好,欢迎来到IT知识分享网。

本课知识点:SpEL语句的书写 (考试内容直接看最后一部分)

一、SpEL语法

1.SpEL概念:

SpEL全称Spring Expression Language,能在运行时构建复杂表达式、存取对象图属性、对象方法调用等等。

2.SpEL的使用:

首先我们先简单说明四个基本概念:(在接下来会进行讲解)

  1. 用户表达式:我们定义的表达式,如1+1!=2
  2. 解析器:ExpressionParser 接口,负责将用户表达式解析成SpEL认识的表达式对象
  3. 表达式对象:Expression接口,SpEL的核心,表达式语言都是围绕表达式进行的
  4. 评估上下文:EvaluationContext 接口,表示当前表达式对象操作的对象,表达式的评估计算是在上下文上进行的。

(1)最基本的字符串输出

 //表达式解析器 ExpressionParser parser = new SpelExpressionParser(); //设置表达式 Expression exp = parser.parseExpression("'hello world'"); String str = (String) exp.getValue(); //第二种获取值的方法 //String str = exp.getValue(String.class); System.out.println(str); 

注意:
pareseExpression()方法中,各参数均由String类型进行传递,即你的表达式外要加” “(双引号)。
在这个例子中,需要注意的是String类型的变量在传递的时候,还要在字符串两边添加’ ‘(单引号),否则解析器的parseExpression()方法将无法识别。

接下来通过Expression对象的getValue()方法获取表达式的值,可以通过强制类型转化或者设置参数来指定表达式结果的返回类型。见源码中getValue方法的定义:

 <T> T getValue(Class<T> desiredResultType) throws EvaluationException;

这是只有一个参数的getValue方法,其参数用来指定返回值类型,值为静态类,如String.class 

接下来看其他类型的表达式:

(2)调用含有方法的字符串

 ExpressionParser exp = parser.parseExpression("'hello world'.charAt(0)"); char ch = (Character) exp.getValue(); System.out.println(ch);

在pareseExpression方法中,””(双引号)中依旧是你传递的参数,但当前’hello world’这个字符串调用了charAt()方法,则” ‘hello world’.charAt(0) “现在是一个Character类型的参数,你应当将返回的结果转化为Character类型,或者在getValue()方法中设置参数为Character.class。

下面两个表达式说明解析器(parseExpression())不仅仅是简单地获取并储存用户表达式:

(3)布尔表达式

 Expression exp = parser.parseExpression("1+1 != 2"); Boolean b = exp.getValue(boolean.class); System.out.println(b);

解析器用户表达式(1+1 != 2)进行解析后,返回一个boolen类型的结果false。说明Expression对象不仅仅是简单储存用户表达式,而是对其进行了处理,后面会根据源码来分析。

(4)针对特定对象解析表达式

在课程文档中,我们有一个角色类Role,接下来我们将使用解析器获取这个类对象的信息。

 //创建角色对象 Role role = new Role(1L, "role_name", "note1"); //设置表达式 ExpressionParser exp = parser.parseExpression("note"); //相当于从role中获取备注信息 String note = (String) exp.getValue(role); System.out.println(note);

注意
getValue()方法有重载, 此时传入的role参数不是指返回值类型。接口定义如下:

 Object getValue(Object rootObject) throws EvaluationException;

3.SpEL执行原理(摘抄)

1.首先定义表达式:“1+2”; 2.定义解析器ExpressionParser实现,SpEL提供默认实现SpelExpressionParser; 2.1.SpelExpressionParser解析器内部使用Tokenizer类进行词法分析,即把字符串流分析为记号流,记号在SpEL使用Token类来表示; 2.2.有了记号流后,解析器便可根据记号流生成内部抽象语法树;在SpEL中语法树节点由SpelNode接口实现代表:如OpPlus表示加操作节点、IntLiteral表示int型字面量节点;使用SpelNodel实现组成了抽象语法树; 2.3.对外提供Expression接口来简化表示抽象语法树,从而隐藏内部实现细节,并提供getValue简单方法用于获取表达式值;SpEL提供默认实现为SpelExpression; 3.定义表达式上下文对象(可选),SpEL使用EvaluationContext接口表示上下文对象,用于设置根对象、自定义变量、自定义函数、类型转换器等,SpEL提供默认实现StandardEvaluationContext; 4.使用表达式对象根据上下文对象(可选)求值(调用表达式对象的getValue方法)获得结果。

4.parseExpression()和getValue()的实现原理

//用于储存分词流 private List<Token> tokenStream; @Override protected SpelExpression doParseExpression(String expressionString, ParserContext context) throws ParseException { try { //读取用户书写的表达式 this.expressionString = expressionString; //定义分词器 Tokenizer tokenizer = new Tokenizer(expressionString); //分词器将字符串拆分为分词流 tokenizer.process(); this.tokenStream = tokenizer.getTokens(); this.tokenStreamLength = this.tokenStream.size(); this.tokenStreamPointer = 0; this.constructedNodes.clear(); //将分词流解析成抽象语法树 SpelNodeImpl ast = eatExpression(); if (moreTokens()) { throw new SpelParseException(peekToken().startPos, SpelMessage.MORE_INPUT, toString(nextToken())); } Assert.isTrue(this.constructedNodes.isEmpty()); //将抽象语法树包装成Expression对象 return new SpelExpression(expressionString, ast, this.configuration); } catch (InternalParseException ex) { throw ex.getCause(); } }

(2)getValue()源码: 

private final SpelNodeImpl ast; public <T> T getValue(EvaluationContext context, @Nullable Class<T> expectedResultType) throws EvaluationException { Assert.notNull(context, "EvaluationContext is required"); //应用活动上下文和解析器的配置 ExpressionState expressionState = new ExpressionState(context, this.configuration); //在上下中抽象语法树进行评估求值 TypedValue typedResultValue = this.ast.getTypedValue(expressionState); checkCompile(expressionState); //将结果进行类型转换 return ExpressionUtils.convertTypedValue(context, typedResultValue, expectedResultType); } 

流程(摘抄):

SpEL基本操作--Week12企业级开源框架课程内容

(考试可以不看这一步)

二、设置环境变量(Context)

1.概念–EvaluationContext(评估上下文)接口:

表示上下文环境,默认实现是StandardEvaluationContext类,使用SetRootObject方法来设置根对象,使用setVariable方法来注册自定义变量,使用registerFunction来注册自定义函数等。

2.实践1:定义变量并引用

 //1.创建表达解析器 ExpressionParser parser = new SpelExpressionPareser(); //2.创建环境变量类 EvaluationContext ctx = new StandardEvaluationContext(); //3.创建一个(任意类型的)变量 List<String> list = new ArrayList<String>(); list.add("value1"); list.add("value2"); //4.给变量环境ctx增加变量"list",值为list--刚才定义的数组 ctx.setVariable("list", list); //5.6.通过表达式去读写环境变量的值 parser.parseExpression("#list[1]").setValue(ctx, "update_value2"); System.out.println(parser.parseExpression("#list[1]").getValue(ctx));

 3.setVariable()解析(源码):

private final Map<String, Object> variables = new HashMap<String, Object>(); public void setVariable(String name, Object value) { //将name和value都装入成员变量variables this.variables.put(name, value); }

你可以在EvaluationContext对象中定义变量,它们被以String name — Object value的形式储存到对象的成员变量variables中。

3.实践2:环境变量根节点、类对象的操作

 //创建表达式解析器 ExpressionParser parser = new SpelExpressionParser(); //创建Role对象 Role role = new Role(1L, "role_name", "note1"); Expression exp = parser.parseExpression("note"); String note = (String) exp.getValue(role); //变量环境类,并且将角色对象role作为其根节点 EvaluationContext ctx = new StandardEvaluationContext(role); //变量环境类操作根节点 parser.parseExpression("note").setValue(ctx, "new_note"); //System.out.println(role.getNote()); //获取备注,这里的String.class指明,我们希望返回的是一个字符串 note = parser.parseExpression("note").getValue(ctx, String.class); System.out.println(note); //调用getRoleName方法 String roleName = parser.parseExpression("getRoleName()") .getValue(ctx, String.class); System.out.println(roleName);

三、总结(应付考试)

对于考试的操作,直接看这部分即可。

1.SpEL使用:

(1)创建表达式解析器:

ExpressionParse parser = new spelExpressionParser();

(2)设置表达式:

Expression exp = parser.parserExpression(“xxx”)
其中,xxx可以是字符串(要加”)、字符、方法、整数、表达式等。

(3)获取表达式的值

Type value = exp.getValue(Type.class);
其中Type是你需要的表达式返回值类型,getValue()中的参数指定这种类型。

(4)特殊情况:获取类对象中的属性值(成员变量)
Expression exp = parser.parserExpression(“成员变量名”);
Type value = exp.getValue(类对象);

 

2.配置上下文环境(Context)

(2)向ctx中添加我们定义的变量:

ctx.setVariable(“name”, value);
name是我们定义的变量名称,value是Object类型的值(可以是任意类型) 

(3)使用解析表达式对ctx中的变量进行赋值

parser.parserExpression(“#name”).setValue(ctx, value);
其中,parser.parserExpression()我们学过,是一个解析表达式(Expression对象),它的值如果是以#开头,则说明它指定一个Context的变量名称。setValue()中的两个变量分别是ctx和你要对名为name的变量赋的值。

(4)创建ctx的根节点:

EvaluationContext ctx = new StandardEvaluationContext(变量/类对象);
在创建StandardEvaluationContext对象时,传入的参数就是它的根节点。

(5)修改根节点的属性值:

parser.parserExpression(“#root”).setValue(ctx, value);
可以在表达式中使用#root表示这个变量。(当然也可以用常规方式)

参考文章:

Spring系列19:SpEL详解 – kongxubihai – 博客园 (cnblogs.com)

玩转Spring中强大的spel表达式! – 知乎 (zhihu.com)

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/131230.html

(0)
上一篇 2025-08-09 16:26
下一篇 2025-08-09 16:33

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信