一、ActionContext
我们知道,ActionContext是Action执行时的上下文,里面存放着Action在执行时需要用到的对象,也称之为广义值栈。Struts2在每次执行Action之前都会创建新的ActionContext,在同一个线程里ActionContext里面的属性是唯一的,这样Action就可以在多线程中使用。
1、Action的多例模式
Action对象的多例模式,示例如下:
import com.opensymphony.xwork2.ActionSupport;
public class HelloWorldAction extends ActionSupport{
private static final long serialVersionUID = 1L;
public HelloWorldAction(){
System.out.println("create new HelloWorldAction");
}
// 默认调用方法
public String execute() {
System.out.println("hello world");
return "index";
}
}
<package name="helloworld" namespace="/" extends="struts-default">
<action name="helloWorldAction" class="com.test.struts2.action.HelloWorldAction">
<result name="index">index.jsp</result>
</action>
</package>
通过上面的示例可以看出,struts2采用的是多例模式,每次访问的时候都会创建一个新的HelloWorldAction
2、ActionContext的线程安全性
ActionContext的线程安全性,示例如下:
ThreadLocal又称为“线程局部变量”,它为每一个使用该变量的线程都提供一个变量值的副本,使每一个线程都可以独立地改变自己的副本,而不会和其它线程的副本冲突。存放在ActionContext里的数据都存放在这个ThreadLocal的属性中,而这个属性只会在对应的当前请求线程中可见,从而保证数据是线程安全的。
3、ActionContext中对象的Map包装
Struts2框架将与Web相关的很多对象重新进行了包装,比如将HttpSession对象重新包装成了一个Map对象,里面存放着Session中的数据,提供这个Map给Action使用,而不用Action直接和底层的HttpSession打交道。也正是因为框架的包装,让Action可以完全的和Web层解耦。示例:
SessionMap session = (SessionMap) ActionContext.getContext()
.get(ServletActionContext.SESSION);
System.out.println("SessionMap session = " + session.getClass().getName());
结果:
SessionMap session = org.apache.struts2.dispatcher.SessionMap
4、ActionContext的获取方式
(1)在自定义的拦截器中:使用ActionInvocation.getInvocationContext()或者使用ActionContext.getContext()
(2)在Action类中:让拦截器注入或者使用ActionContext.getContext()
(3)在非Action类中:让Action类传递参数、使用注入机制注入或者使用ActionContext.getContext()。注意:只有运行在request线程中的代码才能调用ActionContext.getContext(),否则返回的是null
5、ActionContext获取对象方式
(1)HttpServletRequest:请求对象
HttpServletRequest request = (HttpServletRequest) ActionContext.getContext()
.get(ServletActionContext.HTTP_REQUEST);
(2)HttpServletResponse:响应对象
HttpServletResponse response = (HttpServletResponse) ActionContext.getContext()
.get(ServletActionContext.HTTP_RESPONSE);
(3)SessionMap:session对象
SessionMap session = (SessionMap) ActionContext.getContext()
.get(ServletActionContext.SESSION);
(4)ValueStack:值栈对象
ValueStack valueStack = (ValueStack) ActionContext.getContext()
.get(ServletActionContext.VALUE_STACK);
(5)Parameters:参数对象
TreeMap parameters = (TreeMap) ActionContext.getContext().get(ServletActionContext.PARAMETERS);
(6)Application:应用
ApplicationMap application = (ApplicationMap) ActionContext.getContext()
.get(ServletActionContext.APPLICATION);
(7)Local:当前环境
Locale locale = (Locale) ActionContext.getContext()
.get(ServletActionContext.LOCALE);
(8)ActionMapping:ActionMapping的主要功能就是管理Action的信息和管理Action执行完成以后的ActionForward的信息。
ActionMapping action_mapping = (ActionMapping) ActionContext.getContext()
.get(ServletActionContext.ACTION_MAPPING);
(9)DefaultActionInvocation:默认Action执行器
DefaultActionInvocation action_invocation = (DefaultActionInvocation) ActionContext.getContext()
.get(ServletActionContext.ACTION_INVOCATION);
可以通过DefaultActionInvocation获取ActionContext:
ActionContext invocationContext = action_invocation.getInvocationContext();
二、ServletActionContext
这个类直接继承了ActionContext,当然也继承了它父类的很多功能,比如:对OgnlValueStack、Action名字等的访问。
更重要的是,它还提供了直接访问Servlet的相关对象的功能,它可以取得的对象有:
(1)HttpServletRequest:请求对象
HttpServletRequest request = ServletActionContext.getRequest();
(2)HttpServletResponse:响应对象
HttpServletResponse response = ServletActionContext.getResponse();
(3)ActionContext:Action上下文
ActionContext context = ServletActionContext.getContext();
ActionContext actionContext = ServletActionContext.getActionContext(request);
(4)ActionMapping:ActionMapping的主要功能就是管理Action的信息和管理Action执行完成以后的ActionForward的信息。
ActionMapping actionMapping = ServletActionContext.getActionMapping();
(5)PageContext:Page上下文
PageContext pageContext = ServletActionContext.getPageContext();
(6)ServletContext:Servlet上下文
ServletContext servletContext = ServletActionContext.getServletContext();
(7)ValueStack:值栈
ValueStack valueStack = ServletActionContext.getValueStack(request);
三、ActionContext和ServletActionContext的联系
ActionContext和ServletActionContext有着一些重复的功能,都能够获取到Web对象的数据,但是又有些不同。通常情况下,可以这么认为:ActionContext主要负责值的操作;ServletActionContext主要负责获取Servlet对象。那么在Action中,该如何去抉择呢?
建议的原则是:
- 优先使用ActionContext
- 只有ActionContext不能满足功能要求的时候,才使用ServletActionContext
总之,要尽量让Action与Web无关,这对于Action的测试和复用都是极其有好处的。另外还有一点需要注意:在使用ActionContext时,不要在Action的构造函数里使用ActionContext.getContext(),因为这个时候ActionContext里的一些值也许还没有设置,这时通过ActionContext取得的值也许是null。