Spring Expression分析

来源:互联网 发布:评价刘雯 孙菲菲 知乎 编辑:程序博客网 时间:2024/05/17 21:04

一、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是最小单元。

Tokenizerpublicvoid 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 identifierlexIdentifier();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 spacethis.pos++;break;case'\'':lexQuotedStringLiteral();break;case'"':lexDoubleQuotedStringLiteral();break;case0://hit sentinel at end of valuethis.pos++;// will take us to the endbreak;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.        循环每一个token2.        对每一个token进行处理[逻辑清晰,易处理]i.        eatLogicalOrExpression[吃逻辑或表达式or]1.        classOpOr extends Operatora)        publicBooleanTypedValuegetValueInternal(ExpressionStatestate)2.        abstractclass Operator extends SpelNodeImpl3.        classSpelNodeImpl implements SpelNode4.        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 pop2.        (,吃表达示从开头开始吃,)àpush 当前吃的东西 return true pop3.        普通IDENTIFIER,(,eatPossiblyQualifiedId,)push Type引用户 pop4.        普通IDENTIFIER,null,pushnull pop(maybeEatNullReference)5.        普通IDENTIFIER,new,maybeEatConstructorReference, ConstructorReference,pop6.        普通IDENTIFIER,maybeEatMethodOrProperty,maybeEatMethodArgs,参数,为空表示属性,不为空表示为方法7.        普通IDENTIFIER,maybeEatFunctionOrVar,#,方法参数,8.        maybeEatBeanReference,@bean引用9.        maybeEatProjection![10.        maybeEatSelection$[11.        maybeEatSelection[12.        maybeEatInlineList{}x.        如果节点为.,[,?.则请取下一个节点作为CompoundExpression,否则返回SpelNodeImplxi.        Return
 

4、解析语法树 

    依靠SpelNodeImpl子类和EvaluationContext等解析语法树,最终得出值

 

0 0
原创粉丝点击