一、Spring Expression介绍
Spring Expression是Spring框架中一个强大表达式解析语言,支持在运行时动态的解析表达式给对象赋值。Spring Expression支持如下解析功能:
布尔和关系运算符,正则表达式,类表达式,访问属性、数组列表,哈希表,方法调用,关系运算,赋值,调用构造函数,Bean引用,数组构造,内联列表,三元运算符,变量,用户自定义函数,集合操作,模板化表达式。按类型分配可以总结成以下几个类型的解析功能:
1、基本表达式:字面量表达式、关系,逻辑与算数运算表达式、字符串连接及截取表达式、三目运算及Elivis表达式、正则表达式、括号优先级表达式;
2、类相关表达式:类类型表达式、类实例化、instanceof表达式、变量定义及引用、赋值表达式、自定义函数、对象属性存取及安全导航表达式、对象方法调用、Bean引用;
3、集合相关表达式:内联List、内联数组、集合,字典访问、列表,字典,数组修改、集合投影、集合选择;不支持多维内联数组初始化;不支持内联字典定义;
4、其他表达式:模板表达式。
二、Spring Expression模块总体结构
org.springframework.expression:主要是提供表达式解析的接口,如Expression(表达式解析后分割的可求出自身值的表达式接口),ExpressionParser(表达式解析接口),EvaluationContext(表达式评估上下文接口),MethodExecutor(方法调用工具类接口) |
org.springframework.expression.common:定义一些公共的表达式类CompositeStringExpression、LiteralExpression,解析类TemplateAwareExpressionParser,解析工具类ExpressionUtils |
org.springframework.expression.spel:整个spel及其子包是Expression的核心,spel本级包ExpressionState是每个表达式计算状态的一个容器,里面存储上下文,值,表达式rootObject,configuration,activeObject等信息;SpelNode是ast包里头所有类的接口,它是Expression依赖进行求值的工具 |
org.springframework.expression.spel.ast:SpelNode所有子类,进行表达式计算的核心,每个Expression会有一个或多个SpelNode(按运算规则如四则运算规则SpelNode区分父子) |
org.springframework.expression.spel.standard:Spring提供的标准的解析器和表达式,其中Token是表达式语法分析后的最小单元 |
org.springframework.expression.spel.support:表达式解析的一些工具类 |
三、Spring Expression求解的流程
1、单词分解:将表达式字符串分解成不同类型Token对象,Token是最小单元。
Tokenizer
publicvoid process() {
while(this.pos < this.max) {
charch = this.toProcess[this.pos];
if(isAlphabetic(ch)) {
lexIdentifier();//标识符解析
}
else{
switch(ch) {
case'+':
if(isTwoCharToken(TokenKind.INC)) {
pushPairToken(TokenKind.INC);
}
else{
pushCharToken(TokenKind.PLUS);
}
break;
case'_': // the other way to start an identifier
lexIdentifier();
break;
case'-':
if(isTwoCharToken(TokenKind.DEC)) {
pushPairToken(TokenKind.DEC);
}
else{
pushCharToken(TokenKind.MINUS);
}
break;
case':':
pushCharToken(TokenKind.COLON);
break;
case'.':
pushCharToken(TokenKind.DOT);
break;
case',':
pushCharToken(TokenKind.COMMA);
break;
case'*':
pushCharToken(TokenKind.STAR);
break;
case'/':
pushCharToken(TokenKind.DIV);
break;
case'%':
pushCharToken(TokenKind.MOD);
break;
case'(':
pushCharToken(TokenKind.LPAREN);
break;
case')':
pushCharToken(TokenKind.RPAREN);
break;
case'[':
pushCharToken(TokenKind.LSQUARE);
break;
case'#':
pushCharToken(TokenKind.HASH);
break;
case']':
pushCharToken(TokenKind.RSQUARE);
break;
case'{':
pushCharToken(TokenKind.LCURLY);
break;
case'}':
pushCharToken(TokenKind.RCURLY);
break;
case'@':
pushCharToken(TokenKind.BEAN_REF);
break;
case'^':
if(isTwoCharToken(TokenKind.SELECT_FIRST)) {
//组合操作符
pushPairToken(TokenKind.SELECT_FIRST);
}
else{
//指数
pushCharToken(TokenKind.POWER);
}
break;
case'!':
if(isTwoCharToken(TokenKind.NE)) {
pushPairToken(TokenKind.NE);
}
elseif (isTwoCharToken(TokenKind.PROJECT)) {
pushPairToken(TokenKind.PROJECT);
}
else{
pushCharToken(TokenKind.NOT);
}
break;
case'=':
if(isTwoCharToken(TokenKind.EQ)) {
pushPairToken(TokenKind.EQ);
}
else{
pushCharToken(TokenKind.ASSIGN);
}
break;
case'&':
if(!isTwoCharToken(TokenKind.SYMBOLIC_AND)) {
thrownew InternalParseException(new SpelParseException(
this.expressionString,this.pos, SpelMessage.MISSING_CHARACTER,
"&"));
}
pushPairToken(TokenKind.SYMBOLIC_AND);
break;
case'|':
if(!isTwoCharToken(TokenKind.SYMBOLIC_OR)) {
thrownew InternalParseException(new SpelParseException(
this.expressionString,this.pos, SpelMessage.MISSING_CHARACTER,
"|"));
}
pushPairToken(TokenKind.SYMBOLIC_OR);
break;
case'?':
if(isTwoCharToken(TokenKind.SELECT)) {
pushPairToken(TokenKind.SELECT);
}
elseif (isTwoCharToken(TokenKind.ELVIS)) {
pushPairToken(TokenKind.ELVIS);
}
elseif (isTwoCharToken(TokenKind.SAFE_NAVI)) {
pushPairToken(TokenKind.SAFE_NAVI);
}
else{
pushCharToken(TokenKind.QMARK);
}
break;
case'$':
if(isTwoCharToken(TokenKind.SELECT_LAST)) {
pushPairToken(TokenKind.SELECT_LAST);
}
else{
lexIdentifier();
}
break;
case'>':
if(isTwoCharToken(TokenKind.GE)) {
pushPairToken(TokenKind.GE);
}
else{
pushCharToken(TokenKind.GT);
}
break;
case'<':
if(isTwoCharToken(TokenKind.LE)) {
pushPairToken(TokenKind.LE);
}
else{
pushCharToken(TokenKind.LT);
}
break;
case'0':
case'1':
case'2':
case'3':
case'4':
case'5':
case'6':
case'7':
case'8':
case'9':
lexNumericLiteral(ch== '0');
break;
case' ':
case'\t':
case'\r':
case'\n':
//drift over white space
this.pos++;
break;
case'\'':
lexQuotedStringLiteral();
break;
case'"':
lexDoubleQuotedStringLiteral();
break;
case0:
//hit sentinel at end of value
this.pos++;// will take us to the end
break;
case'\\':
thrownew InternalParseException(
newSpelParseException(this.expressionString, this.pos,
SpelMessage.UNEXPECTED_ESCAPE_CHAR));
default:
thrownew IllegalStateException("Cannot handle ("
+Integer.valueOf(ch) + ") '" + ch + "'");
}
}
}
}
2、词法分析
3、 生成语法树
词法分析和生成语法树是同步进行的,词法分析生成Expression,Expression最后按照运算规则生成SpelNodeImpl语法树InternalSpelExpressionParser.doParseExpression()负责单词分解,词法分析,生成语法树。
protectedSpelExpression doParseExpression(String expressionString, ParserContextcontext) throws ParseException {
try{
this.expressionString= expressionString;
//Token分解
Tokenizertokenizer = new Tokenizer(expressionString);
tokenizer.process();
this.tokenStream= tokenizer.getTokens();
this.tokenStreamLength= this.tokenStream.size();
this.tokenStreamPointer= 0;
this.constructedNodes.clear();
//词法分析,生成语法树
SpelNodeImplast = eatExpression();
if(moreTokens()) {
thrownewSpelParseException(peekToken().startpos,SpelMessage.MORE_INPUT,toString(nextToken()));
}
Assert.isTrue(this.constructedNodes.isEmpty());
returnnew SpelExpression(expressionString, ast, this.configuration);
}
catch(InternalParseException ipe) {
throwipe.getCause();
}
}
eatExpression流程:
1. 循环每一个token
2. 对每一个token进行处理[逻辑清晰,易处理]
i. eatLogicalOrExpression[吃逻辑或表达式or]
1. classOpOr extends Operator
a) publicBooleanTypedValue
getValueInternal(ExpressionStatestate)
2. abstractclass Operator extends SpelNodeImpl
3. classSpelNodeImpl implements SpelNode
4. ObjectgetValue(ExpressionState expressionState) throws EvaluationException;
5.
ii. eatLogicalAndExpression[吃逻辑and]
iii. eatRelationalExpression[吃关系(>,>=,<,<=,==,!=,instanceof,matches, between)]
iv. eatSumExpression[吃统计(+-)](这里可以重写+方法,在EvaluationContext复写)
v. eatProductExpression[吃产品*/%]
vi. eatPowerExpression[吃power^]
vii. eatUnaryExpression[号+-!]
viii. eatPrimaryExpression[吃主体]
ix. eatStartNode[开始吃节点]
1. int,long,float,Boolean,stringàpush next return pop
2. (,吃表达示从开头开始吃,)àpush 当前吃的东西 return true pop
3. 普通IDENTIFIER,(,eatPossiblyQualifiedId,)push Type引用户 pop
4. 普通IDENTIFIER,null,pushnull pop(maybeEatNullReference)
5. 普通IDENTIFIER,new,maybeEatConstructorReference, ConstructorReference,pop
6. 普通IDENTIFIER,maybeEatMethodOrProperty,
maybeEatMethodArgs,参数,为空表示属性,不为空表示为方法
7. 普通IDENTIFIER,maybeEatFunctionOrVar,#,方法参数,
8. maybeEatBeanReference,@bean引用
9. maybeEatProjection![
10. maybeEatSelection$[
11. maybeEatSelection[
12. maybeEatInlineList{}
x. 如果节点为.,[,?.则请取下一个节点作为CompoundExpression,否则返回SpelNodeImpl
xi. Return
4、解析语法树
依靠SpelNodeImpl子类和EvaluationContext等解析语法树,最终得出值