您的位置:首页 > 编程语言 > Java开发

Spring表达式语言SpEL

2016-07-11 14:49 666 查看
Spring表达式语言全称为“Spring Expression Language”,缩写为“SpEL”。重要的几个接口:ExpressionParser,EvaluationContext,Expression。

SpEL在求表达式值时一般分为四步:

1)创建解析器:SpEL使用ExpressionParser接口表示解析器,提供SpelExpressionParser默认实现;
2)解析表达式:使用ExpressionParser的parseExpression来解析相应的表达式为Expression对象。
3)构造上下文:准备比如变量定义等等表达式需要的上下文数据。
4)求值:通过Expression接口的getValue方法根据上下文获得表达式值。

例:1+2

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方法)获得结果。

解析的基本表达式:
1.字面量表达式:String,int,long,double,float,boolean,null类型。字符串示例:String str = parser.parseExpression("'hello world'").getValue(String.class);
2.算数运算表达式: SpEL支持加(+)、减(-)、乘(*)、除(/)、求余(%)、幂(^)运算。加法示例:int result = parser.parseExpression("1+2").getValue(Integer.class);
3.关系表达式:等于(==)、不等于(!=)、大于(>)、大于等于(>=)、小于(<)、小于等于(<=),区间(between)运算,如“parser.parseExpression("1>2").getValue(boolean.class);”将返回false;而“parser.parseExpression("1
between {1, 2}").getValue(boolean.class);”将返回true。

4.逻辑表达式:且(and)、或(or)、非(!或NOT)。示例:boolean result
= parser.parseExpression(2>1 and (NOT true or NOT false ).getValue(boolean.class);
 
result是true。    注:不支持&&和||。
5.三目运算及Elivis运算表达式
6.正则表达式:使用“str matches regex,如“'123' matches '\\d{3}'”将返回true。
7.括号优先级表达式:使用“(表达式)”构造,括号里的具有高优先级。

类相关表达式:

1.类类型表达式:使用“T(Type)”来表示java.lang.Class实例,“Type”必须是类全限定名,“java.lang”包除外,即该包下的类可以不指定包名;使用类类型表达式还可以进行访问类静态方法及类静态字段。示例:Class<String> result
= parser.parseExpression("T(String)").getValue(Class.class);
 result是String.class。
2.类实例化:类实例化同样使用java关键字“new”,类名必须是全限定名,但java.lang包内的类型除外,如String、Integer。
示例:String result 1= parser.parseExpression("new String('haha')").getValue(String.class);
 
                    Date result2 = parser.parseExpression("new java.util.Date()").getValue(Date.class);
3.instanceof表达式:SpEL支持instanceof运算符,跟Java内使用同义;如“'haha' instanceof T(String)”将返回true。

4.变量定义及引用:[/b]变量定义通过EvaluationContext接口的setVariable(variableName, value)方法定义;在表达式中使用“#variableName”引用;除了引用自定义变量,SpE还允许引用根对象及当前上下文对象,使用“#root”引用根对象,使用“#this”引用当前上下文对象;
示例:ExpressionParser parser = new SpelExpressionParser();//创建解析器

            EvaluationContext context = new StandardEvaluationContext();//构造上下文

            context.setVariable("variable", "haha");//定义variable

            String result1 = parser.parseExpression("#variable").getValue(context, String.class);//引用自定义变量  result1为"haha"

          context = new StandardEvaluationContext("haha");//构造上下文对象

            String result2 = parser.parseExpression("#root").getValue(context, String.class); //引用跟对象  result2为"haha"
    String result3 = parser.parseExpression("#this").getValue(context, String.class); //引用上下文对象  result3为"haha"
5.自定义函数:目前只支持类静态方法注册为自定义函数;SpEL使用StandardEvaluationContext的registerFunction方法进行注册自定义函数,其实完全可以使用setVariable代替,两者其实本质是一样的。
6.赋值表达式:SpEL即允许给自定义变量赋值,也允许给跟对象赋值,直接使用“#variableName=value”即可赋值。
7.对象方法调用:对象方法调用更简单,跟Java语法一样;如“'haha'.substring(2,4)”将返回“ha”;而对于根对象可以直接调用方法。
8.Bean引用:SpEL支持使用“@”符号来引用Bean,在引用Bean时需要使用BeanResolver接口实现来查找Bean,Spring提供BeanFactoryResolver实现。

集合相关表达式:
1.内联List:从Spring3.0.4开始支持内联List,使用{表达式,……}定义内联List,如“{1,2,3}”将返回一个整型的ArrayList,而“{}”将返回空的List,对于字面量表达式列表,SpEL会使用java.util.Collections.unmodifiableList方法将列表设置为不可修改。

示例:List<Integer> result2 = parser.parseExpression("{}").getValue(List.class);
        //返回不可修改的空list
    List<Integer> result1 = parser.parseExpression("{1,2,3}").getValue(List.class); //返回不可修改的list
(list里有3个元素1,2,3)
    List<List<Integer>> result3 = parser.parseExpression("{{1+2,2+4},{3,4+4}}").getValue(List.class);
  //列表中只要有一个不是字面量表达式,返回原始list(可修改)
    int[] result2 = parser.parseExpression("new int[2]{1,2}").getValue(int[].class);
  //定义一个大小为2的一维数组并初始化 (也可不初始化)
    int[][][] result3 = parser.parseExpression("new
int[1][2][3]").getValue(int[][][].class);
  //定义一个多维数组。
2.集合,字典元素访问:SpEL目前支持所有集合类型和字典类型的元素访问,使用“集合[索引]”访问集合元素,使用“map[key]”访问字典元素;
示例:int result1 = parser.parseExpression("{1,2,3}[0]").getValue(int.class); //result1为1   
 int result2 = parser.parseExpression("#collection[1]").getValue(context2, int.class);
//result2为自定义变量名为collection的集合的第二个变量
int result3 = parser.parseExpression("#map['a']").getValue(context3, int.class); //result3为自定义变量名为map的map集合的键为a对应的值
3.列表,字典,数组元素修改:可以使用赋值表达式或Expression接口的setValue方法修改。
示例:int result1 = parser.parseExpression("#array[1] = 3").getValue(context1, int.class); 
int result3 = parser.parseExpression("#map['a'] = 2").getValue(context3, int.class);
4.集合投影:在SQL中投影指从表中选择出列,而在SpEL指根据集合中的元素中通过选择来构造另一个集合,该集合和原集合具有相同数量的元素;
SpEL使用“(list|map).![投影表达式]”来进行投影运算:
示例:Collection<Integer> result1 =  parser.parseExpression("#collection.![#this+1]").getValue(context1, Collection.class);
 
List<Integer> result2 = parser.parseExpression("#map.![ value+1]").getValue(context2, List.class);
 

在XML定义中使用SpEL:


SpEL支持在Bean定义时注入,默认使用“#{SpEL表达式}”表示,其中“#root”根对象默认可以认为是ApplicationContext,只有ApplicationContext实现默认支持SpEL,获取根对象属性其实是获取容器中的Bean。
示例:   
<bean id="world" class="java.lang.String">

       <constructor-arg value="#{' World!'}"/>

   </bean>

   <bean id="hello1" class="java.lang.String">

       <constructor-arg value="#{'Hello'}#{world}"/>

   </bean> 

   <bean id="hello2" class="java.lang.String">

       <constructor-arg value="#{'Hello' + world}"/>

       <!-- 不支持嵌套的 -->

       <!--<constructor-arg value="#{'Hello'#{world}}"/>-->

   </bean> 

   <bean id="hello3" class="java.lang.String">

       <constructor-arg value="#{'Hello' + @world}"/>

   </bean> 


  模板默认以前缀“#{”开头,以后缀“}”结尾,且不允许嵌套,如“#{'Hello'#{world}}”错误,如“#{'Hello' + world}”中“world”默认解析为Bean。当然可以使用“@bean”引用了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  spring 语言