欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2022-05-18 12:19:45
...

值栈(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)。在用法上,*对象的属性访问,是不需要任何标记前缀的。而其它非*的对象访问,需要使用#标记。

例如:
<s:property value="%{#application.myApplicationKey}" />
<s:property value="%{#session.mySessionKey}" />
<s:property value="%{#request.myRequestKey}" />
<s:property value="%{#parameters.myParameterKey}" /> 


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来指定是个原型模式,而不是单例,这样就解决了线程安全问题。每个线程都是一个新的实例。