Spring Expression分析

12 篇文章 0 订阅

一、Spring Expression介绍

 

Spring ExpressionSpring框架中一个强大表达式解析语言,支持在运行时动态的解析表达式给对象赋值。Spring Expression支持如下解析功能:

布尔和关系运算符,正则表达式,类表达式,访问属性、数组列表,哈希表,方法调用,关系运算,赋值,调用构造函数,Bean引用,数组构造,内联列表,三元运算符,变量,用户自定义函数,集合操作,模板化表达式。按类型分配可以总结成以下几个类型的解析功能:

1、基本表达式:字面量表达式、关系,逻辑与算数运算表达式、字符串连接及截取表达式、三目运算及Elivis表达式、正则表达式、括号优先级表达式; 

2、类相关表达式:类类型表达式、类实例化、instanceof表达式、变量定义及引用、赋值表达式、自定义函数、对象属性存取及安全导航表达式、对象方法调用、Bean引用; 

3、集合相关表达式:内联List、内联数组、集合,字典访问、列表,字典,数组修改、集合投影、集合选择;不支持多维内联数组初始化;不支持内联字典定义; 

4、其他表达式:模板表达式。 

 

二、Spring Expression模块总体结构

org.springframework.expression:主要是提供表达式解析的接口,如Expression(表达式解析后分割的可求出自身值的表达式接口),ExpressionParser(表达式解析接口),EvaluationContext(表达式评估上下文接口),MethodExecutor(方法调用工具类接口)

org.springframework.expression.common:定义一些公共的表达式类CompositeStringExpressionLiteralExpression,解析类TemplateAwareExpressionParser,解析工具类ExpressionUtils

org.springframework.expression.spel:整个spel及其子包是Expression的核心,spel本级包ExpressionState是每个表达式计算状态的一个容器,里面存储上下文,值,表达式rootObjectconfigurationactiveObject等信息;SpelNodeast包里头所有类的接口,它是Expression依赖进行求值的工具

org.springframework.expression.spel.astSpelNode所有子类,进行表达式计算的核心,每个Expression会有一个或多个SpelNode(按运算规则如四则运算规则SpelNode区分父子)

org.springframework.expression.spel.standardSpring提供的标准的解析器和表达式,其中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 生成语法树

      词法分析和生成语法树是同步进行的,词法分析生成ExpressionExpression最后按照运算规则生成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等解析语法树,最终得出值

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值