Skip to content

字面量表达式 (Literal Expressions)

SpEL 支持以下类型的字面量表达式。

字符串 (String)

字符串可以用单引号 (') 或双引号 (") 分隔。要在以单引号括起来的字符串字面量中包含单引号,请使用两个连续的单引号字符。同样,要在以双引号括起来的字符串字面量中包含双引号,请使用两个连续的双引号字符。

数值 (Number)

数值支持负号、科学计数法和点号(小数点)。

  • 整数:支持 intlong
  • 十六进制:支持 intlong
  • 实数:支持 floatdouble
    • 默认情况下,实数使用 Double.parseDouble() 进行解析。

布尔值 (Boolean)

truefalse

Null

null

注意:负数最小值的陷阱

由于 SpEL 的设计和实现机制,字面量数值在内部始终存储为正数。

例如,-2 在内部存储为正数 2,然后在评估表达式时通过计算 0 - 2 的值来进行取反。

这意味着在 SpEL 中无法直接表示等于 Java 中该类型最小值的负数字面量。例如,Java 中 int 的最小值是 Integer.MIN_VALUE(即 -2147483648)。但是,如果你在 SpEL 表达式中包含 -2147483648,系统会抛出异常,提示值 2147483648 无法解析为 int(因为它超过了 Integer.MAX_VALUE2147483647)。

如果你需要在 SpEL 表达式中使用特定类型的最小值,可以引用对应包装类型的 MIN_VALUE 常量,或者进行手动计算。例如,对于整数最小值:

  • T(Integer).MIN_VALUE —— 需要使用 StandardEvaluationContext
  • -2^31 —— 可用于任何类型的 EvaluationContext

以下列表展示了字面量的简单用法。通常情况下,它们不会像这样孤立地使用,而是作为更复杂表达式的一部分——例如,在逻辑比较运算符的一侧或作为方法的参数。

java
ExpressionParser parser = new SpelExpressionParser();

// 评估结果为 "Hello World"
String helloWorld = (String) parser.parseExpression("'Hello World'").getValue();

// 评估结果为 "Tony's Pizza"(使用了单引号转义)
String pizzaParlor = (String) parser.parseExpression("'Tony''s Pizza'").getValue();

double avogadrosNumber = (Double) parser.parseExpression("6.0221415E+23").getValue();

// 评估结果为 2147483647(十六进制)
int maxValue = (Integer) parser.parseExpression("0x7FFFFFFF").getValue();

boolean trueValue = (Boolean) parser.parseExpression("true").getValue();

Object nullValue = parser.parseExpression("null").getValue();
kotlin
val parser = SpelExpressionParser()

// 评估结果为 "Hello World"
val helloWorld = parser.parseExpression("'Hello World'").value as String

// 评估结果为 "Tony's Pizza"(使用了单引号转义)
val pizzaParlor = parser.parseExpression("'Tony''s Pizza'").value as String

val avogadrosNumber = parser.parseExpression("6.0221415E+23").value as Double

// 评估结果为 2147483647(十六进制)
val maxValue = parser.parseExpression("0x7FFFFFFF").value as Int

val trueValue = parser.parseExpression("true").value as Boolean

val nullValue = parser.parseExpression("null").value

补充教学

1. 字符串引号:单引号还是双引号?

虽然 SpEL 本身支持双引号,但在 XML 配置Java 注解中使用 SpEL 时,建议优先使用 单引号

  • 原因:Java 注解属性本身是用双引号括起来的(例如 @Value("#{...}"))。如果在表达式内部再使用双引号,你需要进行繁琐的转义:@Value("#{\"Hello\"}")
  • 使用单引号可以保持代码整洁:@Value("#{'Hello'}")

2. 关于单引号转义的直观理解

SpEL 采用的是类似于 SQL 的转义方式。

  • 如果你想表达 I'm fine,在 SpEL 字符串字面量中应写为 'I''m fine'
  • 这与 Java 的 \' 转义不同,初学者容易在这里犯错。

3. 理解 T(...) 运算符

在上面的“最小值陷阱”中提到了 T(Integer).MIN_VALUE

  • T(...) 是 SpEL 中访问类(Class)的捷径。
  • 它允许你访问静态方法和静态常量。这在处理枚举、常量类或执行数学运算(如 T(Math).PI)时极其有用。

4. 为什么 SpEL 要把负数拆开解析?

这涉及到表达式解析器的通用模式:将 -2 识别为“负号运算符”作用于“字面量 2”。 虽然这导致了最小值表达上的小麻烦,但这极大简化了解析引擎的逻辑,使其能一致地处理 -a(变量取反)和 -2(字面量取反)。

Based on Spring Framework.