Struts2中OGNL、ActionContext和值栈及线程安全浅析

阅读更多

值栈(ValueStack)   
Struts2将OGNL上下文设置为Struts2中的ActionContext(内部使用的仍然是OgnlContext),并将值栈设为OGNL的根对象。    
OGNL上下文中的根对象可以用ONGL表达式以对象名直接访问的,不需要使用任何特殊的“标记”,而引用上下文中的其他对象则需要使用“#”来标记。由于值栈是OGNL上下文中的根对象,因此可以直接访问。那么对于值栈中的对象该如何访问呢?Struts2提供了一个特殊的OGNLPropertyAccessor,它可以自动查找栈内的所有对象(从栈顶到栈底),直接找到一个具有你所查找的属性的对象。也就是说,对于值栈中的任何对象都可以直接访问,而不需要使用“#”。    
值栈中的对象都是OGNL上下文中的根对象。这就是Struts2在OGNL基础上做出的改进。

ActionContext
ActionContext是Action的环境,一次Action调用都会创建一个ActionContext
调用:ActionContext context = ActionContext.getContext()

Struts2对OGNL上下文的概念又做了进一步扩充,在struts2中,OGNL上下文通常如下所示:

                        |--request 

                        | 

                        |--application 

                        | 

context map---|--OgnlValueStack(root) [ user, action, OgnlUtil, ... ] 

                        | 

                        |--session 

                        | 

                        |--attr 

                        | 

                        |--parameters 

在Struts2中,采用标准命名的上下文(Context)来处理OGNL表达式。处理OGNL的顶级对象是一个Map(也叫context map),而OGNL在这个context中就是一个顶级对象(root)。在用法上,顶级对象的属性访问,是不需要任何标记前缀的。而其它非顶级的对象访问,需要使用#标记。

例如:



 


Struts2框架把OGNL Context设置为ActionContext。并且ValueStack作为OGNL的根对象。除value stack之外,Struts2框架还把代表application、session、request这些对象的Map对象也放到ActionContext中去。(这也就是Struts2建议在Action类中不要直接访问Servlet API的原因,他可以通过ActionContext对象来部分代替这些(Servlet API)功能。)



Struts2把页面上的值传到Action里面,这个过程从逻辑上说需要分成两步来完成:

1. 对于每个请求,都建立一个与相应Action对应的ActionContext作为OGNL的上下文环境和ValueStack,并且把Action里面的属性值压入ValueStack,这时的属性值都是初始化值。

2. 在请求进入Action代码前,通过某种通用的机制(就是Struts2的interceptor拦截器机制),搜集页面上传递过来的参数,这里调用的是params拦截器,准确来说是这个拦截器会找Action里面的所有属性的set方法,把页面的Struts2标签的对应名称的属性值set进去,这样Action里面的属性就成功赋值。



设计Struts2的团队初衷就是为了不用和那些Servlet API复杂的请求(Request)、响应(Response)关联在一起。





Struts2的线程安全
一般情况,我们的ActionContext都是通过:ActionContext context = (ActionContext) actionContext.get();来获取的。我们再来看看这里的actionContext对象的创建:static ThreadLocal actionContext = new ActionContextThreadLocal();,ActionContextThreadLocal是实现ThreadLocal的一个内部类。ThreadLocal可以命名为“线程局部变量”,它为每一个使用该变量的线程都提供一个变量值的副本,使每一个线程都可以独立地改变自己的副本,而不会和其它线程的副本冲突。这样,我们ActionContext里的属性只会在对应的当前请求线程中可见,从而保证它是线程安全的。

Struts2的action中就像一个POJO一样,定义了很多的类变量。此时,就使用scope=prototype来指定是个原型模式,而不是单例,这样就解决了线程安全问题。每个线程都是一个新的实例。 

你可能感兴趣的:(Struts2,valuestack,值栈,ActionContext,ongl)