Spring Expression分析
来源:互联网 发布:评价刘雯 孙菲菲 知乎 编辑:程序博客网 时间:2024/05/17 21:04
一、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是最小单元。
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、 生成语法树
词法分析和生成语法树是同步进行的,词法分析生成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. 循环每一个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等解析语法树,最终得出值
- Spring Expression分析
- spring aop 断言expression
- Spring Expression Language (SpEL)
- spring 中的expression
- spring expression注意事项
- Spring Cron Expression
- spring aop中的expression
- Spring Expression Language (Spring 3.0)
- Spring aop expression 星号(*)
- spring aop expression简单说明
- spring aop expression简单说明
- spring aop expression简单说明
- spring aop expression简单说明
- spring aop expression简单说明
- spring aop expression简单说明
- spring aop expression简单说明
- spring aop expression简单说明
- Spring aop expression 简单说明
- 日志14-12-10
- ExtJS学习之路第七步:contentEl与renderTo的区别
- java作业//世界协和时(判断)
- ExtJS学习之路第八步:Window组件
- 多边形的扫描转换之扫描线算法 c++实现 vc6.0控制台
- Spring Expression分析
- OC :代理 协议 委托 数据源的概念
- Java分享角色获取菜单权限(修正版)
- 多线程03_张孝祥-传统线程互斥技术
- unable to run app in simulator
- 将枚举类型转化为字符串
- 自定义UISearchBar注意的问题
- 数字签名是什么?
- java中Scanner类的用法