2014-07-20 Java Web的学习(17)-----struts2(3)----OGNL&ValueStack

1.OGNL是什么?
  OGNL就是表达式引擎,所谓表达式引擎就是处理View层和Controller层之间流转数据.在视图层,既没有数据类型的概念,也没有数据结构的概念.一旦对外展现,都会最终转化为同一的 字符串形式.而Controller(Java)中存在各种 数据类型的数据.这时就需要一整套的数据匹配规则.这种规则就是表达式引擎的最初定义的概念.它的作用就是帮助我们完成这种规则化的表达式与Java对象的相互转化.因而它成为架起MVC各个模块之间数据沟通的桥梁.
  Image
 
   在Java世界中,有许多优秀的表达式引擎.OGNL引擎在其内部实现机制和设计原理上存在许多的亮点, 因而Struts2选择了OGNL框架作为它依赖的表达式引擎,而且在OGNL的基础上做了一定程度的扩展.
   图片1
   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类实现的.
 
3.OGNL的上下文环境(ActionContext)-----数据流体系(相互依存)
 
public class ActionContext implements Serializable {
    //通过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
    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);
    }
}
从上面源码可以得出:
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结构,可以统一数据访问方式.
      QQ拼音截图未命名地方撒
  ps:ActionContext-------SerlverActionContext,struts2提供一个子类继承ActionContext的,与Web容器打交道的方案.
5.当Struts2接受一个请求时.会迅速创建ActionContext对象,ValueStack对象,action对象,然后把action实例对象(UserAction{name,password})存放进ValueStack,所以action的实例变量可以被OGNL访问.
6.ActionContext类中成员变量Map<String,Object> context的结构图:
                 Image [1]
   如果需要访问上下文的对象需要#符号标注命名空间,如#application,#session,#request.注意:需要配合struts2的标签一起使用.
   另外的话OGNL会设定一个根对象(root对象),在struts2中就是OgnlVauleStack(值栈,是一个list集合).如果要访问根对象中对象的属性.则可以忽略#命名空间,直接访问该对象的属性即可.如如果UserAction对象(存在name属性)在值栈中的话,就可以直接<s:property value="name">.至于值栈是什么样的查询规则而又为什么不需要#命名空间?.下面详解:
 
4.ValueStack以及其实现类OgnlValueStack-----对OGNL的扩展
 
ValueStatck是针对OGNL计算的扩展,实际上就是针对OGNL三要素中Root对象所进行的扩展.使得在Struts2在使用ValueStack进行OGNL、计算时,可以将一组对象都视为Root对象.
 
                QQ拼音截图未命名32
OgnlValueStack类的源代码:
public class OgnlValueStack implements Serializable, ValueStack, ClearableValueStack, MemberAccessValueStack {
     //使用装饰模式,将根元素(栈结构)封装在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);
    }
}
 
Image [2]
 

QQ拼音截图未命名1
QQ拼音截图未命名3

QQ拼音截图未命2

你可能感兴趣的:(2014-07-20 Java Web的学习(17)-----struts2(3)----OGNL&ValueStack)