概述
Spring Expression Language,SpEL,類似于Struts2x中使用的OGNL表達式語言,及JSP的EL,能在運作時建構複雜表達式、存取對象圖屬性、對象方法調用等。表達式語言給靜态Java語言增加動态功能。SpEL是單獨子產品,隻依賴于core子產品,可單獨使用,依賴如下,但是一般無需獨立引入,作為spring核心元件,常被其他元件作為基礎依賴,實作若幹功能:如配合配置Bean定義。
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
</dependency>
所有EL都是以
${
為起始、以
}
為結尾的。EL提供
.
和
[]
兩種運算符來導航資料。
SpEL支援如下表達式:
- 基本表達式:字面量表達式、關系,邏輯與算數運算表達式、字元串連接配接及截取表達式、三目運算及Elivis表達式、正規表達式、括号優先級表達式;
- 類相關表達式:類類型表達式、類執行個體化、instanceof表達式、變量定義及引用、指派表達式、自定義函數、對象屬性存取及安全導航表達式、對象方法調用、Bean引用;
- 集合相關表達式:内聯List、内聯數組、集合,字典通路、清單,字典,數組修改、集合投影、集合選擇;不支援多元内聯數組初始化;不支援内聯字典定義;
- 其他表達式:模闆表達式。
注:SpEL表達式中的關鍵字不區分大小寫。
通過執行個體分析SpEL求表達式值的步驟:
public class SpELTest {
@Test
public void helloWorld() {
// 1.建立解析器, 提供SpelExpressionParser預設實作
ExpressionParser parser = new SpelExpressionParser();
// 2.解析表達式, parseExpression方法解析得到Expression對象
Expression expression = parser.parseExpression("('Hello' + ' World').concat(#end)");
// 3.構造上下文, 設定資料
EvaluationContext context = new StandardEvaluationContext();
context.setVariable("end", "!");
// 4.Expression接口的getValue方法
Assert.assertEquals("Hello World!", expression.getValue(context));
}
}
SpEL原理及接口
- 表達式:表達式是表達式語言的核心,是以表達式語言都是圍繞表達式進行的,“幹什麼”;
- 解析器:用于将字元串表達式解析為表達式對象,“誰來幹”;
- 上下文:表達式對象執行的環境,該環境可能定義變量、定義自定義函數、提供類型轉換等等,“在哪幹”;
- 根對象及活動上下文對象:根對象是預設的活動上下文對象,活動上下文對象表示了目前表達式操作的對象,“對誰幹”。
核心流程:
- SpelExpressionParser解析器内部使用Tokenizer類進行詞法分析,即把字元串流分析為記号流,記号在SpEL使用Token類來表示;
- 得到記号流後,解析器便可根據記号流生成内部抽象文法樹;
- 在SpEL中文法樹節點由SpelNode接口實作代表:如OpPlus表示加操作節點、IntLiteral表示int型字面量節點;
- 使用SpelNodel實作組成抽象文法樹;
- 對外提供Expression接口來簡化表示抽象文法樹,進而隐藏内部實作細節,并提供getValue簡單方法用于擷取表達式值;
- SpEL提供預設實作為SpelExpression;
- 定義表達式上下文對象(可選),SpEL使用EvaluationContext接口表示上下文對象,用于設定根對象、自定義變量、自定義函數、類型轉換器等,SpEL提供預設實作StandardEvaluationContext;
public interface ExpressionParser {
Expression parseExpression(String expressionString);
Expression parseExpression(String expressionString, ParserContext context);
}
EvaluationContext接口:
public interface EvaluationContext {
/**
* Return the default root context object against which unqualified
* properties/methods/etc should be resolved. This can be overridden
* when evaluating an expression.
*/
TypedValue getRootObject();
/**
* Return a list of accessors that will be asked in turn to read/write a property.
*/
List<PropertyAccessor> getPropertyAccessors();
/**
* Return a list of resolvers that will be asked in turn to locate a constructor.
*/
List<ConstructorResolver> getConstructorResolvers();
List<MethodResolver> getMethodResolvers();
@Nullable
BeanResolver getBeanResolver();
/**
* Return a type locator that can be used to find types, either by short or
* fully qualified name.
*/
TypeLocator getTypeLocator();
/**
* Return a type converter that can convert (or coerce) a value from one type to another.
*/
TypeConverter getTypeConverter();
/**
* Return a type comparator for comparing pairs of objects for equality.
*/
TypeComparator getTypeComparator();
/**
* Return an operator overloader that may support mathematical operations
* between more than the standard set of types.
*/
OperatorOverloader getOperatorOverloader();
void setVariable(String name, @Nullable Object value);
/**
* Look up a named variable within this evaluation context.
* @param name variable to lookup
* @return the value of the variable, or {@code null} if not found
*/
@Nullable
Object lookupVariable(String name);
}
預設實作是StandardEvaluationContext類,使用setRootObject方法來設定根對象,使用setVariable方法來注冊自定義變量,使用registerFunction來注冊自定義函數等。
SpringExpressions.g
檔案,
.g
字尾名檔案,采用Glagol DSL文法寫的配置檔案。