Preface
这里主要是对Java中的各种常见的表达式注入的各种类型和各种原理的一个较为全面的分析
Ognl(Object-Graph Navigation Language)
brief
背景
一种功能强大的表达式语言,通过它简单一致的表达式语法,可以存取对象的任意属性,调用对象的方法,遍历整个对象的结构图,实现字段类型转化等功能。
特点
OGNL使用Java反射和内省来解决运行时应用程序的对象图
简单使用
下面是一些有关于Ognl语法的一些特别的语法
类静态方法调用和值访问:
@[类全名(包括包路径)]@[方法名|值名]
访问OGNL上下文(OGNL context)和ActionContext
可以直接通过
new
创建一个对象通过
#
符号进行容器变量的访问支持投影和选择
选择:
collection.{X YYY}
,其中X是一个选择操作符,后面则是选择用的逻辑表达式, 选择操作符有三类?
^
$
投影:
collection.{XXX}
,其中XXX是这个集合中每个元素的公共属性Ognl的语法树形式
(expression)(constant) = value
(constant)((expression1)(expression2))
# . @
的区别获取静态函数和变量的时候用@
获取非静态函数用.号获取
获取非静态变量用#获取
对ActionContext
对象解释
ActionContext
是一个上下文对象,是一个以MAP为结构、利用键值对关系来描述对象中的属性以及值的对象
常见的作用域request
session
application
三个独特的作用域
attr:保存着上面三个作用域的所有属性,如果有重复的则以request域中的属性为基准;
paramters:保存的是表单提交的参数;
VALUE_STACK:值栈,保存着valueStack对象,也就是说可以通过ActionContext访问到valueStack中的值;
detail
类似的提供一个可以解析Ongl表达式的例子
因为能够解析Ognl表达式的api有很多,我这里只选择了一种
@RequestMapping("/ognl")
@ResponseBody
public String OgnlTest(@RequestParam(required = false) String expression) {
if (expression == null) {
return "Send request with \"expression\" parameter!";
}
try {
OgnlContext ognlContext = new OgnlContext();
Ognl.getValue(expression, ognlContext, ognlContext.getRoot());
} catch (Exception e) {
return Util.printStack(e);
}
return "OK!";
}
在调用Ognl#getValue
方法进行表达式的解析过程中
将会通过调用parseExpression
方法来进行类似于spel表达式的解析
在spel中是通过进行词法分析生成了一个token流,之后依据该tokens构建了一个AST的结构,进而使用spel中的API进行evaluate
而在Ongl中,在parseExpression
方法中同样是构造了一个AST结构
在ongl中表现为ASTChain类这个数据结构
将不同的语句抽象为一个一个Node结点,这些结点都是SimpleNode
这个抽象类的实现类
类似于方法调用封装为ASTMethod
类结点,而构造方法封装为ASTCtor
类结点
前面是解析Ognl表达式的过程,接下来就是根据得到的ASTChain进行evaluate,也就是在Ognl#getValue
中的逻辑
核心逻辑是循环的调用每一个结点的getValue
方法,其中核心的逻辑是在每一个结点实现的getValueBody
方法中
例如ASTCtor#getValueBody
主要是通过Class.forName获取目标类
而对于方法的调用,主要是封装为ASTMethod
对象,调用目标方法