1.OGNL是什么?
OGNL就是表达式引擎,所谓表达式引擎就是处理View层和Controller层之间流转数据.在视图层,既没有数据类型的概念,也没有数据结构的概念.一旦对外展现,都会最终转化为同一的 字符串形式.而Controller(Java)中存在各种 数据类型的数据.这时就需要一整套的数据匹配规则.这种规则就是表达式引擎的最初定义的概念.它的作用就是帮助我们完成这种规则化的表达式与Java对象的相互转化.因而它成为架起MVC各个模块之间数据沟通的桥梁.
在Java世界中,有许多优秀的表达式引擎.OGNL引擎在其内部实现机制和设计原理上存在许多的亮点, 因而Struts2选择了OGNL框架作为它依赖的表达式引擎,而且在OGNL的基础上做了一定程度的扩展.
OGNL(Object Graph Navigation Language)是一个开源的表达式引擎.通过OGNL,我们能够通过表达式存取Java对象树中的任意属性和调用对象Java树的方法。
所以说,OGNL就是语义字符串与Java对象之间沟通的催化剂.
2.OGNL API
/**
* The struts framework sets the OGNL context to be our ActionContext
* and the value stack to be the OGNL root object.
* (The value stack is a set of several objects
* but to OGNL it appears to be a single object.)
* @author LISAI
*
*/
public class Ognl {
/**
* 通过传入OGNL表达式,在给定的上下文环境.从root对象中取值.
* OGNL不是Struts独有的.解决的问题是:web层弱类型和Java强类型的之间的转换.表达式引擎.
* @param expression
* @param context ------- ActionContext
* @param root ------ ValueStack (虽然是数据结构是栈.A Stack that is implemented using a List)
* @return Object
*/
public static Object getValue( String expression,Map context,Object root){
return null ;
}
/**
* 通过传入OGNL表达式,在给定的上下文环境.向root对象中写值.
* @param expression
* @param context
* @param root
* @return Object
*/
public static void setValue(String expression,Map context,Object root){
}
}
通过上述代码可以发现:OGNL引擎主要干两件事情.取值和存值.而这些操作都必须传入三个参数.以后无论OGNL如何完成复杂的操作,都会映射到这三个参数,通过调用底层引擎完成相关计算.从而完成OGNL功能需要三个要素:
a.表达式(Expression),表达式会规定此次OGNL操作到底要干什么.
b.Root对象.可以理解为OGNL的操作对象.也就是"对谁干",Root对象实际上就是一个Java对象,在struts2中相对应的就是实现ValueStack接口的类OgnlValueStack对象中CompoundRoot root对象.(CompoundRoot类是一个有Java List集合构建的栈的结构,存放一组对象.下面在详细说).The value stack is a set of several objects but to OGNL it appears to be a single object.
c.上下文环境(OgnlContext).有了表达式和Root对象.就已经可以使用OGNL的基本功能.不过,事实上在OGNL内部,所有的操作都会在一个特定的数据环境中运行,这个数据环境就是OGNL的上下文环境(Context)。说的明白一些,就是这个上下文环境规定OGNL的操作"在哪里干",OGNL的上下文环境就是Map结构.之前所提及的Root对象,也会被添加上下文环境中,并且被作为一个特殊的变量进行处理.在Struts2中就是ActionContext类实现的.
a.表达式(Expression),表达式会规定此次OGNL操作到底要干什么.
b.Root对象.可以理解为OGNL的操作对象.也就是"对谁干",Root对象实际上就是一个Java对象,在struts2中相对应的就是实现ValueStack接口的类OgnlValueStack对象中CompoundRoot root对象.(CompoundRoot类是一个有Java List集合构建的栈的结构,存放一组对象.下面在详细说).The value stack is a set of several objects but to OGNL it appears to be a single object.
c.上下文环境(OgnlContext).有了表达式和Root对象.就已经可以使用OGNL的基本功能.不过,事实上在OGNL内部,所有的操作都会在一个特定的数据环境中运行,这个数据环境就是OGNL的上下文环境(Context)。说的明白一些,就是这个上下文环境规定OGNL的操作"在哪里干",OGNL的上下文环境就是Map结构.之前所提及的Root对象,也会被添加上下文环境中,并且被作为一个特殊的变量进行处理.在Struts2中就是ActionContext类实现的.
3.OGNL的上下文环境(ActionContext)-----数据流体系(相互依存)
public class ActionContext implements Serializable {
//通过ThreadLocal设计模式,实现ActionContext一次访问中的数据共享.线程安全
static ThreadLocal<ActionContext> actionContext = new ThreadLocal<ActionContext>();
//通过ThreadLocal设计模式,实现ActionContext一次访问中的数据共享.线程安全
static ThreadLocal<ActionContext> actionContext = new ThreadLocal<ActionContext>();
/**
* Constant for the {@link com.opensymphony.xwork2.util.ValueStack OGNL value stack}.
*/
public static final String VALUE_STACK = ValueStack.VALUE_STACK;
// ActionContext中存储数据的上下文环境,ValueStack就存储其中,也有个名字叫做OgnlContext
* Constant for the {@link com.opensymphony.xwork2.util.ValueStack OGNL value stack}.
*/
public static final String VALUE_STACK = ValueStack.VALUE_STACK;
// ActionContext中存储数据的上下文环境,ValueStack就存储其中,也有个名字叫做OgnlContext
private Map<String, Object> context;
/**
* Stores a value in the current ActionContext. The value can be looked up using the key.
* @param key the key of the value.
* @param value the value to be stored.
*/
public void put(String key, Object value) {
context.put(key, value);
}
/**
* Returns a value that is stored in the current ActionContext by doing a lookup using the value's key.
*
* @param key the key used to find the value.
* @return the value that was found using the key or <tt>null</tt> if the key was not found.
*/
public Object get(String key) {
return context.get(key);
}
/**
* Sets the OGNL value stack.
* 设置ValueStack
* @param stack the OGNL value stack.
*/
public void setValueStack(ValueStack stack) {
put(VALUE_STACK, stack);
}
/**
* Gets the OGNL value stack.
* 获取ValueStack
* @return the OGNL value stack.
*/
public ValueStack getValueStack() {
return (ValueStack) get(VALUE_STACK);
}
}
/**
* Stores a value in the current ActionContext. The value can be looked up using the key.
* @param key the key of the value.
* @param value the value to be stored.
*/
public void put(String key, Object value) {
context.put(key, value);
}
/**
* Returns a value that is stored in the current ActionContext by doing a lookup using the value's key.
*
* @param key the key used to find the value.
* @return the value that was found using the key or <tt>null</tt> if the key was not found.
*/
public Object get(String key) {
return context.get(key);
}
/**
* Sets the OGNL value stack.
* 设置ValueStack
* @param stack the OGNL value stack.
*/
public void setValueStack(ValueStack stack) {
put(VALUE_STACK, stack);
}
/**
* Gets the OGNL value stack.
* 获取ValueStack
* @return the OGNL value stack.
*/
public ValueStack getValueStack() {
return (ValueStack) get(VALUE_STACK);
}
}
从上面源码可以得出:
1.ActionContext
ActionContext是XWork中最重要的概念之一.它提供整个Xwork时间处理的上下文环境,在这个数据环境包含了所有事件处理过程中所需要的数据对象. 所以每一个事件响应,都有一个ActionContext对象的存在与之对应.
2.从源码中,我们可以看到ActionContext真正的数据存储空间,是位于其中Map类型的变量context.ActionContext将所有的数据对象以特定的key值存放在context之中.而ActionContext也提供获取重要元素的快捷方法:如getValueStack,getSession;
3.如何保证线程安全的:ThreadLocal设计模式
4.ActionContext所提供的数据的访问返回的都是Map类型的数据对象,而不是真正的HttpSession等这样纯正的Web容器对象.做到与Web容器无关.
好处:原生的web容器对象的本身不是线程安全的.而通过Xwork的封装。彻底消除这一隐患.
保持所有存储对象的Map结构,可以统一数据访问方式.
ActionContext是XWork中最重要的概念之一.它提供整个Xwork时间处理的上下文环境,在这个数据环境包含了所有事件处理过程中所需要的数据对象. 所以每一个事件响应,都有一个ActionContext对象的存在与之对应.
2.从源码中,我们可以看到ActionContext真正的数据存储空间,是位于其中Map类型的变量context.ActionContext将所有的数据对象以特定的key值存放在context之中.而ActionContext也提供获取重要元素的快捷方法:如getValueStack,getSession;
3.如何保证线程安全的:ThreadLocal设计模式
4.ActionContext所提供的数据的访问返回的都是Map类型的数据对象,而不是真正的HttpSession等这样纯正的Web容器对象.做到与Web容器无关.
好处:原生的web容器对象的本身不是线程安全的.而通过Xwork的封装。彻底消除这一隐患.
保持所有存储对象的Map结构,可以统一数据访问方式.
ps:ActionContext-------SerlverActionContext,struts2提供一个子类继承ActionContext的,与Web容器打交道的方案.
5.当Struts2接受一个请求时.会迅速创建ActionContext对象,ValueStack对象,action对象,然后把action实例对象(UserAction{name,password})存放进ValueStack,所以action的实例变量可以被OGNL访问.
6.ActionContext类中成员变量Map<String,Object> context的结构图:
如果需要访问上下文的对象需要#符号标注命名空间,如#application,#session,#request.注意:需要配合struts2的标签一起使用.
另外的话OGNL会设定一个根对象(root对象),在struts2中就是OgnlVauleStack(值栈,是一个list集合).如果要访问根对象中对象的属性.则可以忽略#命名空间,直接访问该对象的属性即可.如如果UserAction对象(存在name属性)在值栈中的话,就可以直接<s:property value="name">.至于值栈是什么样的查询规则而又为什么不需要#命名空间?.下面详解:
ValueStatck是针对OGNL计算的扩展,实际上就是针对OGNL三要素中Root对象所进行的扩展.使得在Struts2在使用ValueStack进行OGNL、计算时,可以将一组对象都视为Root对象.
OgnlValueStack类的源代码:
protected OgnlValueStack(ValueStack vs, XWorkConverter xworkConverter, CompoundRootAccessor accessor, boolean allowStaticAccess) {
//调用setRoot方法完成初始化
setRoot(xworkConverter, accessor, new CompoundRoot(vs.getRoot()), allowStaticAccess);
}
//真正的OgnlValueStack的初始化过程.
protected void setRoot(XWorkConverter xworkConverter, CompoundRootAccessor accessor, CompoundRoot compoundRoot,
boolean allowStaticMethodAccess) {
//根对象是一个CompoundRoot类型的栈结构
this.root = compoundRoot;
this.securityMemberAccess = new SecurityMemberAccess(allowStaticMethodAccess);
//创建OGNL的上下文
this.context = Ognl.createDefaultContext(this.root, accessor, new OgnlTypeConverterWrapper(xworkConverter), securityMemberAccess);
//设置OGNL上下文的其他相关参数
context.put(VALUE_STACK, this);
Ognl.setClassResolver(context, accessor);
((OgnlContext) context).setTraceEvaluations(false);
((OgnlContext) context).setKeepLastEvaluation(false);
}
}
public class OgnlValueStack implements Serializable, ValueStack, ClearableValueStack, MemberAccessValueStack {
//使用装饰模式,将根元素(栈结构)封装在ValueStack对象内容.
//从外界来看,所有的操作就像针对单一对象的操作.实际在内部,是List形成的栈结构.
CompoundRoot root;
//使用装饰模式,将根元素(栈结构)封装在ValueStack对象内容.
//从外界来看,所有的操作就像针对单一对象的操作.实际在内部,是List形成的栈结构.
CompoundRoot root;
//OnglContext对象
transient Map<String, Object> context ;
//构造函数,这里讲制定OGNL计算所需的参数 protected OgnlValueStack(ValueStack vs, XWorkConverter xworkConverter, CompoundRootAccessor accessor, boolean allowStaticAccess) {
//调用setRoot方法完成初始化
setRoot(xworkConverter, accessor, new CompoundRoot(vs.getRoot()), allowStaticAccess);
}
//真正的OgnlValueStack的初始化过程.
protected void setRoot(XWorkConverter xworkConverter, CompoundRootAccessor accessor, CompoundRoot compoundRoot,
boolean allowStaticMethodAccess) {
//根对象是一个CompoundRoot类型的栈结构
this.root = compoundRoot;
this.securityMemberAccess = new SecurityMemberAccess(allowStaticMethodAccess);
//创建OGNL的上下文
this.context = Ognl.createDefaultContext(this.root, accessor, new OgnlTypeConverterWrapper(xworkConverter), securityMemberAccess);
//设置OGNL上下文的其他相关参数
context.put(VALUE_STACK, this);
Ognl.setClassResolver(context, accessor);
((OgnlContext) context).setTraceEvaluations(false);
((OgnlContext) context).setKeepLastEvaluation(false);
}
}
OgnlValueStack使用了一个典型的装饰模式,真正的其内部起到核心作用的是一个叫做CompoundRoot root的数据结构,可以存储多个对象(栈结构).ValueStack是一个被设计成"栈"的数据结构.并且还是一个具备表达式引擎计算能力的数据结构.OGNL与Stack的结合.
/**
* A Stack that is implemented using a List.
* @author plightbo
* @version $Revision: 894090 $
*/
public class CompoundRoot extends ArrayList {
public CompoundRoot() {
}
public CompoundRoot(List list) {
super(list);
}
public CompoundRoot cutStack(int index) {
return new CompoundRoot(subList(index, size()));
}
public Object peek() {
return get(0);
}
public Object pop() {
return remove(0);
}
public void push(Object o) {
add(0, o);
}
}
* A Stack that is implemented using a List.
* @author plightbo
* @version $Revision: 894090 $
*/
public class CompoundRoot extends ArrayList {
public CompoundRoot() {
}
public CompoundRoot(List list) {
super(list);
}
public CompoundRoot cutStack(int index) {
return new CompoundRoot(subList(index, size()));
}
public Object peek() {
return get(0);
}
public Object pop() {
return remove(0);
}
public void push(Object o) {
add(0, o);
}
}