4. Spring 表达式语言(SpEL)
The Spring Expression Language (“SpEL” for short) is a powerful expression language that supports querying and
manipulating an object graph at runtime.
Spring 表达式语言(简称“SpEL”)是一种强大的表达式语言,支持在运行时查询和操作对象图。
The language syntax is similar to Unified EL but offers additional features, most notably method invocation and basic
string templating functionality.
语言语法类似于统一 EL,但提供了额外的功能,最显著的是方法调用和基本字符串模板功能。
While there are several other Java expression languages available — OGNL, MVEL, and JBoss EL, to name a few — the Spring
Expression Language was created to provide the Spring community with a single well supported expression language that
can be used across all the products in the Spring portfolio.
尽管有几种其他的 Java 表达式语言可用——例如 OGNL、MVEL 和 JBoss EL——Spring 表达式语言被创建出来,旨在为 Spring
社区提供一个单一且得到良好支持的通用表达式语言,该语言可用于 Spring 产品组合中的所有产品。
Its language features are driven by the requirements of the projects in the Spring portfolio, including tooling
requirements for code completion support within the Spring Tools for Eclipse. That said, SpEL
is based on a technology-agnostic API that lets other expression language implementations be integrated, should the need
arise.
其语言特性由 Spring 投资组合中项目的需求驱动,包括对 Spring Tools for Eclipse 中代码补全支持的工具要求。话虽如此,SpEL
基于一个技术无关的 API,允许在需要时集成其他表达式语言实现。
While SpEL serves as the foundation for expression evaluation within the Spring portfolio, it is not directly tied to
Spring and can be used independently. To be self contained, many of the examples in this chapter use SpEL as if it were
an independent expression language.
虽然 SpEL 是 Spring 系列中表达式评估的基础,但它并不直接与 Spring 绑定,可以独立使用。为了自包含,本章中的许多示例都像使用独立的表达式语言一样使用
SpEL。
This requires creating a few bootstrapping infrastructure classes, such as the parser. Most Spring users need not deal
with this infrastructure and can, instead, author only expression strings for evaluation.
这需要创建几个引导基础设施类,例如解析器。大多数 Spring 用户无需处理此基础设施,而只需编写用于评估的表达式字符串即可。
An example of this typical use is the integration of SpEL into creating XML or annotation-based bean definitions, as
shown in Expression support for defining bean definitions.
这是一个此类典型用法的示例,即将 SpEL 集成到创建基于 XML 或注解的 bean 定义中,如表达式支持定义 bean 定义所示。
This chapter covers the features of the expression language, its API, and its language syntax. In several places,
Inventor and Society classes are used as the target objects for expression evaluation. These class declarations and
the data used to populate them are listed at the end of the chapter.
本章涵盖了表达式语言的功能、其 API 及其语言语法。在几个地方,使用 Inventor 和 Society
类作为表达式评估的目标对象。这些类声明以及用于填充它们的数据列在章节末尾。
The expression language supports the following functionality:
表达式语言支持以下功能:
Literal expressions 文字表达式
Boolean and relational operators
布尔和关系运算符
Regular expressions 正则表达式
Class expressions 类表达式
Accessing properties, arrays, lists, and maps
访问属性、数组、列表和映射
Method invocation 方法调用
Relational operators 关系运算符
Assignment 任务
Calling constructors 调用构造函数
Bean references 豆引用
Array construction 数组构造
Inline lists 行内列表
Inline maps 行内地图
Ternary operator 三元运算符
Variables 变量
User-defined functions 用户定义函数
Collection projection 集合投影
Collection selection 收藏选择
Templated expressions 模板表达式
This section introduces the simple use of SpEL interfaces and its expression language. The complete language reference
can be found in Language Reference.
本节介绍了 SpEL 接口的简单使用及其表达式语言。完整的语言参考可以在语言参考中找到。
The following code introduces the SpEL API to evaluate the literal string expression, Hello World.
以下代码介绍了 SpEL API 来评估字面字符串表达式, Hello World 。
1
The value of the message variable is 'Hello World'.
消息变量的值为 'Hello World' 。
1
The value of the message variable is 'Hello World'.
The SpEL classes and interfaces you are most likely to use are located in the org.springframework.expression package
and its sub-packages, such as spel.support.
SpEL 类和接口您最可能使用的是位于 org.springframework.expression 包及其子包中,例如 spel.support 。
The ExpressionParser interface is responsible for parsing an expression string. In the preceding example, the
expression string is a string literal denoted by the surrounding single quotation marks. The Expression interface is
responsible for evaluating the previously defined expression string. Two exceptions that can be thrown, ParseException
and EvaluationException, when calling parser.parseExpression and exp.getValue, respectively.
ExpressionParser 接口负责解析表达式字符串。在上一个示例中,表达式字符串是一个由周围单引号表示的字符串字面量。
Expression 接口负责评估之前定义的表达式字符串。在分别调用 parser.parseExpression 和 exp.getValue 时,可能会抛出
ParseException 和 EvaluationException 两个异常。
SpEL supports a wide range of features, such as calling methods, accessing properties, and calling constructors.
SpEL 支持广泛的功能,例如调用方法、访问属性和调用构造函数。
In the following example of method invocation, we call the concat method on the string literal:
在以下方法调用的示例中,我们在字符串字面量上调用 concat 方法:
1
The value of message is now 'Hello World!'.
message 的值现在是'Hello World!'。
1
The value of message is now 'Hello World!'.
The following example of calling a JavaBean property calls the String property Bytes:
以下调用 JavaBean 属性的示例调用的是 String 属性 Bytes :
1
This line converts the literal to a byte array.
这一行将文本转换为字节数组。
1
This line converts the literal to a byte array.
SpEL also supports nested properties by using the standard dot notation (such as prop1.prop2.prop3) and also the
corresponding setting of property values. Public fields may also be accessed.
SpEL 也支持使用标准点符号(如 prop1.prop2.prop3 )进行嵌套属性,并且还可以设置属性值。公共字段也可以访问。
The following example shows how to use dot notation to get the length of a literal:
以下示例展示了如何使用点符号来获取字面量的长度:
1
'Hello World'.bytes.length gives the length of the literal.
'Hello World'.bytes.length 返回字面量的长度。
1
'Hello World'.bytes.length gives the length of the literal.
The String’s constructor can be called instead of using a string literal, as the following example shows:
字符串构造函数可以代替使用字符串字面量,如下例所示:
1
Construct a new String from the literal and make it be upper case.
构建一个新的 String ,并将其转换为大写。
1
Construct a new String from the literal and make it be upper case.
Note the use of the generic method: public <T> T getValue(Class<T> desiredResultType). Using this method removes the
need to cast the value of the expression to the desired result type. An EvaluationException is thrown if the value
cannot be cast to the type T or converted by using the registered type converter.
The more common usage of SpEL is to provide an expression string that is evaluated against a specific object instance (
called the root object). The following example shows how to retrieve the name property from an instance of the
Inventor class or create a boolean condition:
EvaluationContext 4.1.1. 理解EvaluationContextThe EvaluationContext interface is used when evaluating an expression to resolve properties, methods, or fields and to
help perform type conversion. Spring provides two implementations.
EvaluationContext 接口用于在评估表达式时解析属性、方法或字段,并帮助执行类型转换。Spring 提供了两种实现。
SimpleEvaluationContext: Exposes a subset of essential SpEL language features and configuration options, for
categories of expressions that do not require the full extent of the SpEL language syntax and should be meaningfully
restricted.
SimpleEvaluationContext :暴露了 SpEL 语言功能集的一部分和配置选项,用于不需要 SpEL
语言完整语法的表达式类别,应进行有意义的限制。
Examples include but are not limited to data binding expressions and property-based filters.
示例包括但不限于数据绑定表达式和基于属性的过滤器。
StandardEvaluationContext: Exposes the full set of SpEL language features and configuration options. You can use it
to specify a default root object and to configure every available evaluation-related strategy.
StandardEvaluationContext :公开了 SpEL 语言的全部特性和配置选项。您可以使用它来指定默认根对象,并配置每个可用的评估相关策略。
SimpleEvaluationContext is designed to support only a subset of the SpEL language syntax. It excludes Java type
references, constructors, and bean references. It also requires you to explicitly choose the level of support for
properties and methods in expressions. By default, the create() static factory method enables only read access to
properties. You can also obtain a builder to configure the exact level of support needed, targeting one or some
combination of the following:
SimpleEvaluationContext 仅支持 SpEL 语言语法的子集。它不包括 Java 类型引用、构造函数和 bean
引用。它还要求您在表达式中显式选择对属性和方法的支持级别。默认情况下, create()
静态工厂方法仅启用对属性的读取访问。您还可以获取一个构建器来配置所需的确切支持级别,针对以下一个或多个组合:
Custom PropertyAccessor only (no reflection)
自定义 PropertyAccessor 仅(无反射)
Data binding properties for read-only access
数据绑定属性,仅限只读访问
Data binding properties for read and write
数据绑定属性,用于读取和写入
By default, SpEL uses the conversion service available in Spring core (
org.springframework.core.convert.ConversionService). This conversion service comes with many built-in converters for
common conversions but is also fully extensible so that you can add custom conversions between types. Additionally, it
is generics-aware.
默认情况下,SpEL 使用 Spring 核心中可用的转换服务( org.springframework.core.convert.ConversionService
)。此转换服务包含许多内置的转换器,用于常见的转换,但同时也完全可扩展,以便您可以在类型之间添加自定义转换。此外,它还支持泛型。
This means that, when you work with generic types in expressions, SpEL attempts conversions to maintain type correctness
for any objects it encounters.
这意味着,当你在表达式中使用泛型类型时,SpEL 会尝试转换以保持遇到任何对象时的类型正确性。
What does this mean in practice? Suppose assignment, using setValue(), is being used to set a List property. The
type of the property is actually List<Boolean>. SpEL recognizes that the elements of the list need to be converted to
Boolean before being placed in it. The following example shows how to do so:
实际上这意味着什么?假设使用 setValue() 进行赋值,用于设置 List 属性。属性的类型实际上是 List<Boolean> 。SpEL
识别出在将其放入之前,列表的元素需要转换为 Boolean 。以下示例展示了如何进行转换:
4.1.2. 解析器配置
It is possible to configure the SpEL expression parser by using a parser configuration object (
org.springframework.expression.spel.SpelParserConfiguration). The configuration object controls the behavior of some
of the expression components. For example, if you index into an array or collection and the element at the specified
index is null, SpEL can automatically create the element. This is useful when using expressions made up of a chain of
property references.
可以通过使用解析器配置对象( org.springframework.expression.spel.SpelParserConfiguration )来配置 SpEL
表达式解析器。配置对象控制某些表达式组件的行为。例如,如果您在数组或集合中索引并指定索引处的元素是 null ,SpEL
可以自动创建该元素。这在使用由属性引用链组成的表达式时非常有用。
If you index into an array or list and specify an index that is beyond the end of the current size of the array or list,
SpEL can automatically grow the array or list to accommodate that index.
如果您索引到一个数组或列表并指定一个超出当前数组或列表大小的索引,SpEL 可以自动扩展数组或列表以容纳该索引。
In order to add an element at the specified index, SpEL will try to create the element using the element type’s default
constructor before setting the specified value. If the element type does not have a default constructor, null will be
added to the array or list. If there is no built-in or custom converter that knows how to set the value, null will
remain in the array or list at the specified index. The following example demonstrates how to automatically grow the
list:
为了在指定索引处添加元素,SpEL 将尝试使用元素类型的默认构造函数创建元素,然后再设置指定的值。如果元素类型没有默认构造函数,将在数组或列表中添加
null 。如果没有内置或自定义转换器知道如何设置值, null 将保留在数组或列表的指定索引处。以下示例演示了如何自动扩展列表:
Spring Framework 4.1 includes a basic expression compiler. Expressions are usually interpreted, which provides a lot of
dynamic flexibility during evaluation but does not provide optimum performance.
Spring Framework 4.1 包含一个基本的表达式编译器。表达式通常被解释,这在评估期间提供了很多动态灵活性,但并不提供最佳性能。
For occasional expression usage, this is fine, but, when used by other components such as Spring Integration,
performance can be very important, and there is no real need for the dynamism.
偶尔使用表达方式,这没问题,但是当其他组件如 Spring Integration 使用时,性能可能非常重要,实际上并不需要真正的动态性。
The SpEL compiler is intended to address this need. During evaluation, the compiler generates a Java class that embodies
the expression behavior at runtime and uses that class to achieve much faster expression evaluation.
SpEL 编译器旨在满足这一需求。在评估过程中,编译器生成一个 Java
类,该类体现了表达式在运行时的行为,并使用该类实现更快的表达式评估。
Due to the lack of typing around expressions, the compiler uses information gathered during the interpreted evaluations
of an expression when performing compilation.
由于缺乏围绕表达式的打字,编译器在执行编译时使用在表达式解释评估期间收集到的信息。
For example, it does not know the type of a property reference purely from the expression, but during the first
interpreted evaluation, it finds out what it is.
例如,它不能仅从表达式中知道属性引用的类型,但在第一次解释性评估期间,它会找出它的类型。
Of course, basing compilation on such derived information can cause trouble later if the types of the various expression
elements change over time. For this reason, compilation is best suited to expressions whose type information is not
going to change on repeated evaluations.
当然,如果各种表达式元素的类型随时间变化,基于这种派生信息进行编译可能会在以后造成麻烦。因此,编译最适合那些在重复评估中类型信息不会改变的表达式。
Consider the following basic expression:
考虑以下基本表达式:
someArray[0].someProperty.someOtherProperty < 0.1
Because the preceding expression involves array access, some property de-referencing, and numeric operations, the
performance gain can be very noticeable.
因为前面的表达式涉及数组访问、一些属性解引用和数值运算,性能提升可能非常明显。
In an example micro benchmark run of 50000 iterations, it took 75ms to evaluate by using the interpreter and only 3ms
using the compiled version of the expression.
在一个包含 50000 次迭代的示例微基准测试中,使用解释器评估耗时 75 毫秒,而使用编译后的表达式版本仅需 3 毫秒。
The compiler is not turned on by default, but you can turn it on in either of two different ways. You can turn it on by
using the parser configuration process (discussed earlier) or by using a Spring
property when SpEL usage is embedded inside another component. This section discusses both of these options.
编译器默认未开启,但您可以通过两种不同的方式将其开启。您可以通过使用解析器配置过程(前面已讨论)或在使用 SpEL 嵌入到另一个组件时使用
Spring 属性来开启它。本节将讨论这两种选项。
The compiler can operate in one of three modes, which are captured in the
org.springframework.expression.spel.SpelCompilerMode enum. The modes are as follows:
编译器可以在三种模式之一中运行,这些模式在 org.springframework.expression.spel.SpelCompilerMode 枚举中被捕获。模式如下:
OFF (default): The compiler is switched off.
OFF (默认):编译器已关闭。
IMMEDIATE: In immediate mode, the expressions are compiled as soon as possible. This is typically after the first
interpreted evaluation.
IMMEDIATE : 在立即模式下,表达式会尽快编译。这通常是在第一次解释评估之后。
If the compiled expression fails (typically due to a type changing, as described earlier), the caller of the
expression evaluation receives an exception.
如果编译的表达式失败(通常是由于类型改变,如前所述),调用表达式评估的调用者会收到一个异常。
MIXED: In mixed mode, the expressions silently switch between interpreted and compiled mode over time.
MIXED :在混合模式下,表达式会随着时间的推移在解释模式和编译模式之间静默切换。
After some number of interpreted runs, they switch to compiled form and, if something goes wrong with the compiled
form (such as a type changing, as described earlier), the expression automatically switches back to interpreted form
again.
在经过一定数量的解释执行后,它们切换到编译形式,如果编译形式出现问题(如类型改变,如前所述),表达式会自动切换回解释形式。
Sometime later, it may generate another compiled form and switch to it. Basically, the exception that the user gets in
IMMEDIATE mode is instead handled internally.
稍后,它可能生成另一种编译形式并切换到它。基本上,用户在 IMMEDIATE 模式下遇到的异常将由内部处理。
IMMEDIATE mode exists because MIXED mode could cause issues for expressions that have side effects. If a compiled
expression blows up after partially succeeding, it may have already done something that has affected the state of the
system.
IMMEDIATE 模式存在是因为 MIXED
模式可能会对具有副作用的表达式造成问题。如果编译后的表达式在部分成功后崩溃,它可能已经做了某些影响系统状态的事情。
If this has happened, the caller may not want it to silently re-run in interpreted mode, since part of the expression
may be running twice.
如果发生这种情况,调用者可能不希望它在解释模式下静默重新运行,因为表达式的一部分可能运行了两次。
After selecting a mode, use the SpelParserConfiguration to configure the parser. The following example shows how to do
so:
选择模式后,使用 SpelParserConfiguration 配置解析器。以下示例展示了如何操作:
When you specify the compiler mode, you can also specify a classloader (passing null is allowed). Compiled expressions
are defined in a child classloader created under any that is supplied.
当您指定编译器模式时,也可以指定一个类加载器(允许传递 null)。编译表达式定义在为任何提供的类加载器下创建的子类加载器中。
It is important to ensure that, if a classloader is specified, it can see all the types involved in the expression
evaluation process.
确保如果指定了类加载器,它可以看到表达式评估过程中涉及的所有类型,这是很重要的。
If you do not specify a classloader, a default classloader is used (typically the context classloader for the thread
that is running during expression evaluation).
如果您未指定类加载器,则使用默认类加载器(通常是表达式评估期间运行的线程的上下文类加载器)。
The second way to configure the compiler is for use when SpEL is embedded inside some other component and it may not be
possible to configure it through a configuration object. In these cases, it is possible to set the
spring.expression.compiler.mode property via a JVM system property (or via the
SpringProperties
mechanism) to one of the SpelCompilerMode enum values (off, immediate, or mixed).
第二种配置编译器的方式是在 SpEL 嵌入到其他组件内部,可能无法通过配置对象进行配置时使用。在这种情况下,可以通过 JVM 系统属性(或通过
SpringProperties 机制)将 spring.expression.compiler.mode 属性设置为 SpelCompilerMode 枚举值之一( off 、
immediate 或 mixed )。
Since Spring Framework 4.1, the basic compilation framework is in place. However, the framework does not yet support
compiling every kind of expression. The initial focus has been on the common expressions that are likely to be used in
performance-critical contexts.
自 Spring 框架 4.1
以来,基本的编译框架已经建立。然而,该框架尚不支持编译所有类型的表达式。最初的焦点一直集中在可能在性能关键环境中使用的常见表达式上。
The following kinds of expression cannot be compiled at the moment:
以下这类表达式目前无法编译:
Expressions involving assignment
涉及赋值的表达式
Expressions relying on the conversion service
依赖于转换服务的表达式
Expressions using custom resolvers or accessors
使用自定义解析器或访问器表达式
Expressions using selection or projection
选择或投影的表达式
More types of expressions will be compilable in the future.
未来将支持更多类型的表达式进行编译。
4.2. 在 Bean 定义中的表达式
You can use SpEL expressions with XML-based or annotation-based configuration metadata for defining BeanDefinition
instances. In both cases, the syntax to define the expression is of the form #{ <expression string> }.
您可以使用基于 XML 或基于注解的配置元数据与 SpEL 表达式来定义 BeanDefinition 实例。在这两种情况下,定义表达式的语法形式为
#{ <expression string> } 。
4.2.1. XML 配置
A property or constructor argument value can be set by using expressions, as the following example shows:
属性或构造函数参数值可以通过使用表达式来设置,如下例所示:
All beans in the application context are available as predefined variables with their common bean name. This includes
standard context beans such as environment (of type org.springframework.core.env.Environment) as well as
systemProperties and systemEnvironment (of type Map<String, Object>) for access to the runtime environment.
所有应用程序上下文中的豆类都作为预定义变量可用,其名称为通用豆名。这包括标准上下文豆类,如 environment (类型为
org.springframework.core.env.Environment ),以及用于访问运行时环境的 systemProperties 和 systemEnvironment (类型为
Map<String, Object> )。
The following example shows access to the systemProperties bean as a SpEL variable:
以下示例展示了如何将 systemProperties bean 作为 SpEL 变量进行访问:
Note that you do not have to prefix the predefined variable with the # symbol here.
注意,在这里您不需要在预定义变量前加上 # 符号。
You can also refer to other bean properties by name, as the following example shows:
您也可以通过名称引用其他 bean 属性,如下例所示:
4.2.2. 注解配置
To specify a default value, you can place the @Value annotation on fields, methods, and method or constructor
parameters.
为了指定默认值,您可以在字段、方法和方法或构造函数参数上放置 @Value 注释。
The following example sets the default value of a field:
以下示例设置字段的默认值:
The following example shows the equivalent but on a property setter method:
以下示例显示了在属性设置器方法中的等效操作:
Autowired methods and constructors can also use the @Value annotation, as the following examples show:
自动注入的方法和构造函数也可以使用 @Value 注解,如下例所示:
This section describes how the Spring Expression Language works. It covers the following topics:
本节描述了 Spring 表达式语言的工作原理。它涵盖了以下主题:
Properties, Arrays, Lists, Maps, and Indexers
属性、数组、列表、映射和索引器
The Elvis Operator The Elvis Operator (注意:"Elvis Operator" 是一个编程术语,通常指的是 Elvis 逻辑运算符,因此这里没有进行翻译。)
4.3.1. 文字表达式
SpEL supports the following types of literal expressions.
SpEL 支持以下类型的字面量表达式。
strings 字符串
numeric values: integer (int or long), hexadecimal (int or long), real (float or double)
数值:整数( int 或 long ),十六进制( int 或 long ),实数( float 或 double )
boolean values: true or false
布尔值: true 或 false
null
Strings can delimited by single quotation marks (') or double quotation marks ("). To include a single quotation
mark within a string literal enclosed in single quotation marks, use two adjacent single quotation mark characters.
字符串可以用单引号( ' )或双引号( " )分隔。要在单引号括起来的字符串字面量中包含单引号,请使用两个相邻的单引号字符。
Similarly, to include a double quotation mark within a string literal enclosed in double quotation marks, use two
adjacent double quotation mark characters.
同样,要在双引号内的字符串字面量中包含一个双引号,请使用两个相邻的双引号字符。
Numbers support the use of the negative sign, exponential notation, and decimal points. By default, real numbers are
parsed by using Double.parseDouble().
数字支持使用负号、指数表示法和小数点。默认情况下,实数通过使用 Double.parseDouble() 进行解析。
The following listing shows simple usage of literals. Typically, they are not used in isolation like this but, rather,
as part of a more complex expression — for example, using a literal on one side of a logical comparison operator or as
an argument to a method.
以下列表展示了字面量的简单用法。通常,它们不会像这样单独使用,而是作为更复杂表达式的一部分——例如,在逻辑比较运算符的一侧使用字面量,或将字面量作为方法参数。
4.3.2. 属性、数组、列表、映射和索引器
Navigating with property references is easy. To do so, use a period to indicate a nested property value. The instances
of the Inventor class, pupin and tesla, were populated with data listed in
the Classes used in the examples section. To navigate "down" the object graph and get
Tesla’s year of birth and Pupin’s city of birth, we use the following expressions:
使用属性引用进行导航很简单。要做到这一点,使用点号来表示嵌套属性值。 Inventor 类的实例 pupin 和 tesla
被填充了在示例部分中使用的类中列出的数据。要导航对象图“向下”并获取特斯拉的出生年份和普平的出生城市,我们使用以下表达式:
Case insensitivity is allowed for the first letter of property names. Thus, the expressions in the above example may be
written as Birthdate.Year + 1900 and PlaceOfBirth.City, respectively. In addition, properties may optionally be
accessed via method invocations — for example, getPlaceOfBirth().getCity() instead of placeOfBirth.city.
属性名称的首字母不区分大小写。因此,上述示例中的表达式可以分别写成 Birthdate.Year + 1900 和 PlaceOfBirth.City
。此外,属性可以通过方法调用可选地访问——例如,使用 getPlaceOfBirth().getCity() 而不是 placeOfBirth.city 。
The contents of arrays and lists are obtained by using square bracket notation, as the following example shows:
数组与列表的内容通过使用方括号表示法获取,如下例所示:
The contents of maps are obtained by specifying the literal key value within the brackets. In the following example,
because keys for the officers map are strings, we can specify string literals:
地图内容通过在括号内指定文字键值来获取。在以下示例中,因为 officers 地图的键是字符串,我们可以指定字符串字面量:
You can directly express lists in an expression by using {} notation.
您可以直接使用 {} 符号在表达式中表示列表。
{} by itself means an empty list. For performance reasons, if the list is itself entirely composed of fixed literals,
a constant list is created to represent the expression (rather than building a new list on each evaluation).
{} 本身表示一个空列表。出于性能考虑,如果列表本身完全由固定字面量组成,则会创建一个常量列表来表示该表达式(而不是在每次评估时构建一个新的列表)。
You can also directly express maps in an expression by using {key:value} notation. The following example shows how to
do so:
您也可以使用 {key:value} 符号直接在表达式中表示地图。以下示例展示了如何操作:
{:} by itself means an empty map. For performance reasons, if the map is itself composed of fixed literals or other
nested constant structures (lists or maps), a constant map is created to represent the expression (rather than building
a new map on each evaluation).
{:}
本身表示一个空映射。出于性能考虑,如果映射本身由固定字面量或其他嵌套常量结构(列表或映射)组成,则创建一个常量映射来表示该表达式(而不是在每次评估时构建一个新的映射)。
Quoting of the map keys is optional (unless the key contains a period (.)). The examples above do not use quoted
keys.
引用地图键是可选的(除非键包含点( . ))。上面的示例没有使用引号键。
4.3.5. 数组构造
You can build arrays by using the familiar Java syntax, optionally supplying an initializer to have the array populated
at construction time. The following example shows how to do so:
您可以使用熟悉的 Java 语法来构建数组,可选地提供一个初始化器,以便在构造时填充数组。以下示例展示了如何这样做:
You cannot currently supply an initializer when you construct a multi-dimensional array.
您目前无法在构造多维数组时提供初始化器。
You can invoke methods by using typical Java programming syntax. You can also invoke methods on literals. Variable
arguments are also supported. The following examples show how to invoke methods:
您可以使用典型的 Java 编程语法调用方法。您还可以在字面量上调用方法。也支持可变参数。以下示例显示了如何调用方法:
The Spring Expression Language supports the following kinds of operators:
Spring 表达式语言支持以下类型的操作符:
The relational operators (equal, not equal, less than, less than or equal, greater than, and greater than or equal) are
supported by using standard operator notation. The following listing shows a few examples of operators:
关系运算符(等于、不等于、小于、小于等于、大于、大于等于)通过使用标准运算符符号支持。以下列表展示了几个运算符的示例:
Greater-than and less-than comparisons against null follow a simple rule: null is treated as nothing (that is NOT as
zero). As a consequence, any other value is always greater than null (X > null is always true) and no other value
is ever less than nothing (X < null is always false).
大于和小于比较遵循简单规则: null 被视为无(即不是零)。因此,任何其他值总是大于 null ( X > null 总是 true
),并且没有其他值会小于无( X < null 总是 false )。
If you prefer numeric comparisons instead, avoid number-based null comparisons in favor of comparisons against zero (
for example, X > 0 or X < 0).
如果您更喜欢数字比较,请避免基于数字的 null 比较,而应选择与零的比较(例如, X > 0 或 X < 0 )。
In addition to the standard relational operators, SpEL supports the instanceof and regular expression-based matches
operator. The following listing shows examples of both:
除了标准的比较运算符外,SpEL 还支持基于 instanceof 和基于正则表达式的 matches 运算符。以下列表展示了这两个运算符的示例:
Be careful with primitive types, as they are immediately boxed up to their wrapper types. For example,
1 instanceof T(int) evaluates to false, while 1 instanceof T(Integer) evaluates to true, as expected.
小心原始类型,因为它们会立即装箱成它们的包装类型。例如, 1 instanceof T(int) 等于 false ,而 1 instanceof T(Integer)
等于 true ,正如预期的那样。
Each symbolic operator can also be specified as a purely alphabetic equivalent. This avoids problems where the symbols
used have special meaning for the document type in which the expression is embedded (such as in an XML document). The
textual equivalents are:
每个符号运算符也可以指定为纯字母等效。这避免了在表达式嵌入的文档类型(如 XML 文档)中使用的符号具有特殊意义的问题。文本等效为:
lt (<)lt ( < )
gt (>)gt ( > )
le (<=)le ( <= )
ge (>=)ge ( >= )
eq (==)eq ( == )
ne (!=)ne ( != )
div (/)div ( / )
mod (%)mod ( % )
not (!).not ( ! )。
All of the textual operators are case-insensitive.
所有文本操作符均不区分大小写。
SpEL supports the following logical operators:
SpEL 支持以下逻辑运算符:
and (&&)and ( && )
or (||)or ( || )
not (!)not ( ! )
The following example shows how to use the logical operators:
以下示例展示了如何使用逻辑运算符:
You can use the addition operator (+) on both numbers and strings. You can use the subtraction (-), multiplication (
*), and division (/) operators only on numbers. You can also use the modulus (%) and exponential power (^)
operators on numbers. Standard operator precedence is enforced. The following example shows the mathematical operators
in use:
您可以在数字和字符串上使用加法运算符( + )。您只能在数字上使用减法( - )、乘法( * )和除法( / )运算符。您还可以在数字上使用取模(
% )和指数幂( ^ )运算符。标准运算符优先级得到执行。以下示例显示了使用中的数学运算符:
To set a property, use the assignment operator (=). This is typically done within a call to setValue but can also be
done inside a call to getValue. The following listing shows both ways to use the assignment operator:
设置属性时,请使用赋值运算符( = )。这通常在调用 setValue 时完成,但也可以在调用 getValue 时完成。以下列表显示了使用赋值运算符的两种方式:
You can use the special T operator to specify an instance of java.lang.Class (the type). Static methods are invoked
by using this operator as well. The StandardEvaluationContext uses a TypeLocator to find types, and the
StandardTypeLocator (which can be replaced) is built with an understanding of the java.lang package. This means that
T() references to types within the java.lang package do not need to be fully qualified, but all other type
references must be. The following example shows how to use the T operator:
您可以使用特殊的 T 操作符来指定 java.lang.Class (类型)的实例。静态方法也可以通过使用此操作符来调用。
StandardEvaluationContext 使用 TypeLocator 来查找类型,而 StandardTypeLocator (可以替换)是基于对 java.lang
包的理解构建的。这意味着在 java.lang 包内对类型的 T() 引用不需要完全限定,但所有其他类型引用都必须完全限定。以下示例展示了如何使用
T 操作符:
You can invoke constructors by using the new operator. You should use the fully qualified class name for all types
except those located in the java.lang package (Integer, Float, String, and so on). The following example shows
how to use the new operator to invoke constructors:
您可以使用 new 运算符调用构造函数。对于不在 java.lang 包( Integer 、 Float 、 String
等)中的所有类型,您应该使用完全限定的类名。以下示例展示了如何使用 new 运算符调用构造函数:
You can reference variables in the expression by using the #variableName syntax. Variables are set by using the
setVariable method on EvaluationContext implementations.
您可以通过使用 #variableName 语法在表达式中引用变量。变量通过在 EvaluationContext 实现上使用 setVariable 方法来设置。
Valid variable names must be composed of one or more of the following supported characters.
有效的变量名必须由以下支持的字符组成一个或多个。
letters: A to Z and a to z
字母: A 至 Z 和 a 至 z
digits: 0 to 9数字: 0 至 9
underscore: _下划线: _
dollar sign: $美元符号: $
The following example shows how to use variables.
以下示例展示了如何使用变量。
#this and#root Variables#this 和 #root 变量
The #this variable is always defined and refers to the current evaluation object (against which unqualified references
are resolved). The #root variable is always defined and refers to the root context object. Although #this may vary
as components of an expression are evaluated, #root always refers to the root. The following examples show how to use
the #this and #root variables:
#this 变量始终定义,并指向当前评估对象(未限定引用将针对此对象进行解析)。 #root 变量始终定义,并指向根上下文对象。尽管
#this 可能会随着表达式组件的评估而变化,但 #root 总是指向根。以下示例展示了如何使用 #this 和 #root 变量:
You can extend SpEL by registering user-defined functions that can be called within the expression string. The function
is registered through the EvaluationContext. The following example shows how to register a user-defined function:
您可以通过注册用户定义的函数来扩展 SpEL,这些函数可以在表达式字符串中调用。函数通过 EvaluationContext
进行注册。以下示例展示了如何注册一个用户定义的函数:
For example, consider the following utility method that reverses a string:
例如,考虑以下一个反转字符串的实用方法:
You can then register and use the preceding method, as the following example shows:
您可以根据以下示例进行注册和使用上述方法:
If the evaluation context has been configured with a bean resolver, you can look up beans from an expression by using
the @ symbol. The following example shows how to do so:
如果评估上下文已配置了 Bean 解析器,您可以通过使用 @ 符号从表达式中查找 Bean。以下示例展示了如何操作:
To access a factory bean itself, you should instead prefix the bean name with an & symbol. The following example shows
how to do so:
要访问工厂 bean 本身,您应该用 & 符号作为 bean 名称的前缀。以下示例展示了如何这样做:
4.3.13. 三元运算符(如果-那么-否则)
You can use the ternary operator for performing if-then-else conditional logic inside the expression. The following
listing shows a minimal example:
您可以使用三元运算符在表达式中执行 if-then-else 条件逻辑。以下列表显示了一个最小示例:
In this case, the boolean false results in returning the string value 'falseExp'. A more realistic example
follows:
在这种情况下,布尔值 false 导致返回字符串值 'falseExp' 。以下是一个更现实的例子:
See the next section on the Elvis operator for an even shorter syntax for the ternary operator.
查看下一节关于 Elvis 操作符的部分,以获取三元操作符的更短语法。
4.3.14. Elvis 操作符
The Elvis operator is a shortening of the ternary operator syntax and is used in
the Groovy language. With the ternary operator syntax, you
usually have to repeat a variable twice, as the following example shows:
Elvis 运算符是三元运算符语法的缩写,用于 Groovy 语言中。使用三元运算符语法时,通常需要重复一个变量两次,如下例所示:
Instead, you can use the Elvis operator (named for the resemblance to Elvis' hair style). The following example shows
how to use the Elvis operator:
相反,您可以使用 Elvis 运算符(因其与猫王发型相似而得名)。以下示例展示了如何使用 Elvis 运算符:
The following listing shows a more complex example:
以下列表显示了一个更复杂的示例:
You can use the Elvis operator to apply default values in expressions. The following example shows how to use the Elvis
operator in a @Value expression:
您可以使用 Elvis 运算符在表达式中应用默认值。以下示例展示了如何在 @Value 表达式中使用 Elvis 运算符:
This will inject a system property pop3.port if it is defined or 25 if not.
这将注入一个系统属性 pop3.port ,如果已定义,否则为 25。
4.3.15. 安全导航操作符
The safe navigation operator is used to avoid a NullPointerException and comes from
the Groovy language. Typically, when you have a
reference to an object, you might need to verify that it is not null before accessing methods or properties of the
object. To avoid this, the safe navigation operator returns null instead of throwing an exception.
安全导航操作符用于避免 NullPointerException ,并源自 Groovy 语言。通常,当你有一个对象的引用时,你可能需要在访问对象的方法或属性之前验证它不是
null。为了避免这种情况,安全导航操作符返回 null 而不是抛出异常。
The following example shows how to use the safe navigation operator:
以下示例展示了如何使用安全导航运算符:
4.3.16. 收集选择
Selection is a powerful expression language feature that lets you transform a source collection into another collection
by selecting from its entries.
选择是一个强大的表达式语言特性,允许您通过从其条目中选择来将源集合转换成另一个集合。
Selection uses a syntax of .?[selectionExpression]. It filters the collection and returns a new collection that
contains a subset of the original elements. For example, selection lets us easily get a list of Serbian inventors, as
the following example shows:
选择使用语法 .?[selectionExpression] 。它过滤集合并返回一个包含原始元素子集的新集合。例如,选择使我们能够轻松地获取塞尔维亚发明家的列表,如下例所示:
Selection is supported for arrays and anything that implements java.lang.Iterable or java.util.Map. For a list or
array, the selection criteria is evaluated against each individual element. Against a map, the selection criteria is
evaluated against each map entry (objects of the Java type Map.Entry). Each map entry has its key and value
accessible as properties for use in the selection.
选择支持数组以及实现 java.lang.Iterable 或 java.util.Map 的任何内容。对于列表或数组,选择标准将针对每个单独的元素进行评估。对于映射,选择标准将针对每个映射条目(Java
类型的 Map.Entry 对象)进行评估。每个映射条目都可以将其 key 和 value 作为属性访问,用于选择。
The following expression returns a new map that consists of those elements of the original map where the entry’s value
is less than 27:
以下表达式返回一个新的映射,该映射包含原始映射中值小于 27 的条目:
In addition to returning all the selected elements, you can retrieve only the first or the last element. To obtain the
first element matching the selection, the syntax is .^[selectionExpression]. To obtain the last matching selection,
the syntax is .$[selectionExpression].
除了返回所有选定的元素外,您还可以仅检索第一个或最后一个元素。要获取与选择匹配的第一个元素,语法是
.^[selectionExpression] 。要获取与选择匹配的最后一个元素,语法是 .$[selectionExpression] 。
4.3.17. 收集投影
Projection lets a collection drive the evaluation of a sub-expression, and the result is a new collection. The syntax
for projection is .![projectionExpression]. For example, suppose we have a list of inventors but want the list of
cities where they were born. Effectively, we want to evaluate 'placeOfBirth.city' for every entry in the inventor list.
The following example uses projection to do so:
投影允许一个集合驱动子表达式的评估,结果是一个新的集合。投影的语法是 .![projectionExpression]
。例如,假设我们有一个发明家列表,但想要出生城市的列表。实际上,我们想要评估发明家列表中每个条目的'placeOfBirth.city'
。以下示例使用投影来实现这一点:
Projection is supported for arrays and anything that implements java.lang.Iterable or java.util.Map. When using a
map to drive projection, the projection expression is evaluated against each entry in the map (represented as a Java
Map.Entry). The result of a projection across a map is a list that consists of the evaluation of the projection
expression against each map entry.
投影支持数组以及实现了 java.lang.Iterable 或 java.util.Map 的任何内容。当使用映射驱动投影时,投影表达式将对映射中的每个条目(表示为
Java Map.Entry )进行评估。映射上投影的结果是一个列表,它由对映射中每个条目进行投影表达式评估的结果组成。
4.3.18. 表达式模板
Expression templates allow mixing literal text with one or more evaluation blocks. Each evaluation block is delimited
with prefix and suffix characters that you can define. A common choice is to use #{ } as the delimiters, as the
following example shows:
表达式模板允许将文本字面量与一个或多个评估块混合。每个评估块由您定义的前缀和后缀字符分隔。一个常见的选项是使用 #{ }
作为分隔符,如下例所示:
The string is evaluated by concatenating the literal text 'random number is ' with the result of evaluating the
expression inside the #{ } delimiter (in this case, the result of calling that random() method). The second argument
to the parseExpression() method is of the type ParserContext. The ParserContext interface is used to influence how
the expression is parsed in order to support the expression templating functionality. The definition of
TemplateParserContext follows:
字符串通过连接字面文本 'random number is ' 和在 #{ } 分隔符内评估的表达式的结果来评估(在这种情况下,调用该 random()
方法的返回结果)。 parseExpression() 方法的第二个参数是 ParserContext 类型。使用 ParserContext
接口来影响表达式如何被解析,以支持表达式模板功能。 TemplateParserContext 的定义如下:
4.4. 示例中使用的类
This section lists the classes used in the examples throughout this chapter.
本节列出了本章示例中使用的类。
PlaceOfBirth.java
PlaceOfBirth.kt
出生地.java 出生地.kt
Society.java
Society.kt
Society.java Society.kt