SpELWord格式文档下载.docx
- 文档编号:20016967
- 上传时间:2023-01-15
- 格式:DOCX
- 页数:20
- 大小:38.51KB
SpELWord格式文档下载.docx
《SpELWord格式文档下载.docx》由会员分享,可在线阅读,更多相关《SpELWord格式文档下载.docx(20页珍藏版)》请在冰豆网上搜索。
getBytes()'
.bytes"
byte[]bytes=(byte[])exp.getValue();
Spel还支持嵌套属性,使用标准点符号,即prop1.prop2.prop3和属性值的设置。
也可以直接调用公共字段。
getBytes().length'
.bytes.length"
intlength=(Integer)exp.getValue();
也可以直接使用Spring构造器,而不是字符串形式的Spring
newString('
helloworld'
).toUpperCase()"
Stringmessage=exp.getValue(String.class);
需要注意的是使用通用方法public<
T>
TgetValue(Class<
desiredResultType)。
使用此方法不需要将表达式的值转换为所需的结果类型。
如果该值不能转换为类型T或使用注册的类型转换器转换,则将抛出EvaluationException。
更加通用的做法是提供一个专门类型对象(成为根对象)作为表达式字符串的评估对象。
至于具体使用那种方式,取决于字符串表达式每次调用是否不允许改变表达式的值,换句话说第一种方式每次都是new对象,而下面的方式是在同一个对象中。
在下面的示例中,我们从Inventor类的实例中得到name属性值。
//创建一个Calendar对象,并设置日期
GregorianCalendarc=newGregorianCalendar();
c.set(1856,7,9);
//Inventor是一个自定义JavaBean,构造器参数为name,birthday及nationality。
Inventortesla=newInventor("
NikolaTesla"
c.getTime(),"
Serbian"
name"
EvaluationContextcontext=newStandardEvaluationContext(tesla);
Stringname=(String)exp.getValue(context);
在最后一行中,name的值将被设置为"
,StandardEvaluationContext类可以设置哪个对象的name属性将参与评估。
这就是第二种方法的使用场景,即根对象不太会改变,通过评估上下文对象(EvaluationContext)简单的把根对象设置一次。
如果根对象随时会发生改变,则可以在每次调用getValue时提供该对象,如下例所示:
Stringname=(String)exp.getValue(tesla);
在这种情况下,Inventor的tesla对象实例将直接提供给gatValue方法,表达式评估的基础架构将在内部构建和管理默认的评估上下文,而不需要显示的提供了。
StandardEvaluationContext构造的开销比较昂贵,但在重复使用时,它会建立缓存,以便能够更快地执行后续表达式评估。
因此,最好是在需要缓存和重复使用的时候来构建它,而不是每个表达式评估都建立一个新的。
在某种情况下,可能需要对评估上下文进行配置,同时在getValue方法中又指定了不同的根对象,getValue允许在同一次调用中两者都指定,此时传递给getValue的根对象将覆盖评估上下文中指定的任何对象(可能null)。
单独使用SpEL时,需要创建解析器,解析表达式,还可能创建评估上下文及根对象。
但更常见的做法是仅使用表达式字符串作为配置的一部分。
在这种情况下,解析器,评估上下文,根对象和任何预定义的变量都是隐式设置的,除用户有特殊要求外,表达式之外的对象均不要指定。
作为最后一个介绍性示例,使用上个示例中的Inventor对象来显示布尔运算符的使用。
name=='
NikolaTesla'
booleanresult=exp.getValue(context,Boolean.class);
//评估为true
EvaluationContext接口
EvaluationContext接口主要用于解析属性、方法、字段及协助类型转换时,开箱即用,EvaluationContext通过类反射来操作对象,缓存java.lang.reflect.Method,java.lang.reflect.Field,和java.lang.reflect.Constructor实例来提高性能。
可以通过调用StandardEvaluationContext接口的setRootObject方法来设置根对象,或者通过构造器参数将根对象进行设置以待评估。
还可以使用setVariable()和registerFunction()方法指定将在表达式中使用的变量和函数。
StandardEvaluationContext还可以注册自定义的ConstructorResolvers,MethodResolvers和PropertyAccessors,以扩展SpEL如何评估表达式。
相关请参考这些类的JavaDoc了解更多详细信息。
类型转换
默认情况下,SpEL使用Spring核心(org.springframework.core.convert.ConversionService)中提供的转换服务。
此转换服务附带许多转换器,内置了常用的转换,但也可自行扩展,因此可以添加类型之间的自定义转换。
此外,它具有泛型感知的关键功能,这意味着在使用表达式中的泛型类型时,SpEL将尝试转换正确的对象类型。
这在实践中意味着什么呢?
假如利用setValue方法设置一个List属性,属性的实际类型是List<
Boolean>
,SpEL将知道列表元素需要转换为Boolean类型。
如下例所示:
classSimple{
publicList<
booleanList=newArrayList<
();
}
Simplesimple=newSimple();
simple.booleanList.add(true);
StandardEvaluationContextsimpleContext=newStandardEvaluationContext(simple);
//此处用一个字符串形式的false是可以的,SpEL的转换服务会知道需要将它转换为Boolean类型
parser.parseExpression("
booleanList[0]"
).setValue(simpleContext,"
false"
//b将为false
Booleanb=simple.booleanList.get(0);
解析器配置
可以使用解析器配置对象(org.springframework.expression.spel.SpelParserConfiguration)来配置SpEL表达式解析器。
解析器配置对象可以控制一些表达式组件的行为,比如索引到数组或集合中的元素为null,则可以自动创建元素,当在使用一组由属性链表达式时是非常有用的,如果索引到的数组或集合超出了列表的大小,则可以自动的扩展数组或集合的长度以满足索引要求。
classDemo{
String>
list;
//打开:
//-自动为null引用构造
//-自动增长集合
SpelParserConfigurationconfig=newSpelParserConfiguration(true,true);
ExpressionParserparser=newSpelExpressionParser(config);
Expressionexpression=parser.parseExpression("
list[3]"
Demodemo=newDemo();
Objecto=expression.getValue(demo);
//demo.list现在有4个实体元素
//每个元素是一个空的String
SpEL编译
SpringFramework4.1包含一个基本的表达式编译器。
表达式通常被解释为在评估过程中提供了大量的动态灵活性,但不能提供最佳性能。
偶尔使用一次表达式也许还可以接受,但像被SpringIntegration组件一样使用时,性能就显得非常重要,而没有真正的实现动态。
新的SpEL编译器旨在满足这一需求。
编译器将在评估过程中生成一个真正的Java类,体现了表达式的行为,并使用它来实现更快的表达式求值。
由于在表达式中缺少类型的表达(表达式不是真正通过键盘输入的代码),所以编译器在执行编译时会在表达式的解释性评估期间收集的信息。
例如,它不仅仅是从表达式中知道属性引用的类型,而是在第一个解释性评估过程中会发现它是什么。
当然,如果各种表达式元素的类型随着时间的推移而变化,那么基于此信息的编译可能会导致麻烦。
因此,编译最适合于重复评估类型信息不会改变的表达式。
对于这样的表达式:
someArray[0].someProperty.someOtherProperty<
0.1
这涉及到数组访问,某些属性和数字操作,性能增益可以非常明显。
在50000次迭代的微型基准运行示例中,解释器只需要75ms进行翻译,使用编译后的表达式只需要3ms。
编译器配置
默认情况下,编译器未打开,但有两种方法可以打开它。
可以使用先前讨论的解析器配置过程或者当将SpEL使用嵌入到另一个组件中时通过系统属性打开它。
本节讨论这些选项。
首先要明白,编译器可以运行几种模式,在枚举(org.springframework.expression.spel.SpelCompilerMode)中可以得到。
枚举值如下:
●OFF:
编译器关闭;
这是默认值。
●IMMEDIATE:
在即时模式下,表达式将尽快编译。
这通常是在第一次解释性评估之后。
如果编译的表达式失败(通常是由于类型更改,如上所述),则在表达式求值的调用时会抛出异常。
●MIXED:
在混合模式下,表达式随着时间的推移在解释模式和编译模式之间静默地切换。
经过一些解释运行后,它们将切换到编译形式,如果编译后的表单出现问题(如上所述改变类型),表达式将自动重新切换回解释形式。
稍后,它可能生成另一个编译表单并切换到上面。
基本上,用户进入即时模式(IMMEDIATE)的异常是内部处理。
之所以要存在即时(IMMEDIATE)模式,是因为混合模式(MIXED)在表达式问题上可能会产生副作用,如果表达式在部分编译成功时受到冲击,此时可能已经发生了影响系统状态的操作,如果发生此类事件,调用者可能并不希望隐式的切换到解释模式重新运行,因为这样的话,部分表达式会被运行两次。
当编译器模式选择后,使用SpelParserConfiguration来配置解析器:
SpelParserConfigurationconfig=newSpelParserConfiguration(SpelCompilerMode.IMMEDIATE,this.getClass().getClassLoader());
SpelExpressionParserparser=newSpelExpressionParser(config);
Expressionexpr=parser.parseExpression("
payload"
MyMessagemessage=newMyMessage();
Objectpayload=expr.getValue(message);
当指定编译器模式时,也可以指定一个类加载器(允许传递null)。
编译后的表达式将被定义在以任何提供的方式创建的子类加载器中。
指定一个类加载器是很重要的,因为这样在表达式评估处理的时候对所有涉及到的类型才可见,如果没有指定,则使用运行时线程的上下文类加载器,
当SpEL被嵌入到其他组件中时,此时无法通过编程方式来配置对象时,可以通过使用系统属性piler.mode的方式来配置编译器,属性值为SpelCompilerMode的枚举值之一(off、immediate或mixed)。
编译器限制
在spring框架4.1中有基本的编译框架。
然而,框架不支持编译每一种表达式。
重点会关注在通用的表达式可以在一些严酷性能的上下文中运行。
这是这些表达式不能被编译:
●用于分配的表达式
●依赖转换服务的表达式
●使用自定义解析器或访问器的表达式
●使用选择或映射的表达式
在未来越来越多类型的表达式将会被编译。
表达式在Bean定义中的支持
本次调研不涉及此部分的内容,因此未翻译。
表达式语言参考
文本表达式
支持文本表达式的类型有字符串、数值(整数,实数,十六进制)、布尔型和空(null)。
字符串使用单引号分隔,如果文本中含有单引号,则以两个单引号代替(转义)。
下面的示例显示了文本的简单用法,一般不会这样使用,而是作为用于相对复杂表达式的一部分,比如作为逻辑运算中的比较对象。
//evalsto"
HelloWorld"
StringhelloWorld=(String)parser.parseExpression("
).getValue();
doubleavogadrosNumber=(Double)parser.parseExpression("
6.0221415E+23"
//evalsto2147483647
intmaxValue=(Integer)parser.parseExpression("
0x7FFFFFFF"
booleantrueValue=(Boolean)parser.parseExpression("
true"
ObjectnullValue=parser.parseExpression("
null"
数字支持使用负号,指数符号和小数点。
一般使用Double.parseDouble()解析实数。
Properties,Arrays,Lists,Maps,Indexers
使用属性引用很简单,只需要一个“.”来表示嵌套属性值。
例如Inventor的两个实例pupin和tesla,被填充好数据后,我们用这种表达式方式得到tesla的出生年份和pupin的出生城市:
//evalsto1856
intyear=(Integer)parser.parseExpression("
Birthdate.Year+1900"
).getValue(context);
Stringcity=(String)parser.parseExpression("
placeOfBirth.City"
属性名的第一个字母不区分大小写,数组和集合的元素内容使用方括号的方式进行获取。
//InventionsArray
StandardEvaluationContextteslaContext=newStandardEvaluationContext(tesla);
//evaluatesto"
Inductionmotor"
Stringinvention=parser.parseExpression("
inventions[3]"
).getValue(
teslaContext,String.class);
//MembersList
StandardEvaluationContextsocietyContext=newStandardEvaluationContext(ieee);
Stringname=parser.parseExpression("
Members[0].Name"
societyContext,String.class);
//ListandArraynavigation
Wirelesscommunication"
Members[0].Inventions[6]"
Map的内容是通过方括号中使用文本作为键值进行获取,此时,Map类型对象Officers的键值是字符串类型,因此我们可以这样做:
//官职字典表
Inventorpupin=parser.parseExpression("
Officers['
president'
]"
societyContext,Inventor.class);
Idvor"
Stringcity=parser.parseExpression("
].PlaceOfBirth.City"
//settingvalues
advisors'
][0].PlaceOfBirth.Country"
).setValue(
societyContext,"
Croatia"
内联List
集合/数组可以直接在表达式中使用“{}”符号来表示。
//evaluatestoaJavalistcontainingthefournumbers
Listnumbers=(List)parser.parseExpression("
{1,2,3,4}"
ListlistOfLists=(List)parser.parseExpression("
{{'
a'
'
b'
},{'
x'
y'
}}"
“{}”表示一个空的集合/数组,出于性能原因,如果列表本身完全由固定文字组成,则会创建一个常量列表来表示表达式,而不是在每次评估的时候都建立一个新的集合/数组
内联Map
可以使用{key:
value}表示法直接在表达式中表示Map。
//evaluatestoaJavamapcontainingthetwoentries
MapinventorInfo=(Map)parser.parseExpression("
{name:
Nikola'
dob:
10-July-1856'
}"
MapmapOfMaps=(Map)parser.parseExpression("
{first:
N
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- SpEL