ActionContext实现原理
StrutsPrepareAndExecuteFilter 【http://www.tuicool.com/articles/NVNbYn】
struts2 和 struts1 的一个重要区别就是它进行了 Action 类和 Servlet 的解耦。
又提供了获取 Servlet API 的其它通道,就是 ActionContext (还有个 ServletActionContext ,其实 ServletActionContext 只是 ActionContext 的一个子类而已)。源码为证:public class ServletActionContext extends ActionContext implements StrutsStatics。
ActionContext 是 Action 执行时的上下文,可以看作是一个容器,并且这个容器只是一个 Map。
在ActionContext容器中存放的是 Action 在执行时需要用到的 VALUE_STACK 、 ACTION_NAME 、 SESSION 、 APPLICATION 、 ACTION_INVOCATION 等等对象,还可以存放自定义的一些对象。
在一个请求的处理过程拦截器、 action 类和 result 中任何时候获取的 ActionContext 都是跟当前请求绑定那一个。
首先是 ActionContext 类的源码:
public class ActionContext implements Serializable{
static ThreadLocal actionContext = new ThreadLocal();
public static final String ACTION_NAME = "com.opensymphony.xwork2.ActionContext.name";
public static final String VALUE_STACK = "com.opensymphony.xwork2.util.ValueStack.ValueStack";
public static final String SESSION = "com.opensymphony.xwork2.ActionContext.session";
public static final String APPLICATION = "com.opensymphony.xwork2.ActionContext.application";
public static final String PARAMETERS = "com.opensymphony.xwork2.ActionContext.parameters";
public static final String LOCALE = "com.opensymphony.xwork2.ActionContext.locale";
public static final String TYPE_CONVERTER = "com.opensymphony.xwork2.ActionContext.typeConverter";
public static final String ACTION_INVOCATION = "com.opensymphony.xwork2.ActionContext.actionInvocation";
public static final String CONVERSION_ERRORS = "com.opensymphony.xwork2.ActionContext.conversionErrors";
public static final String CONTAINER = "com.opensymphony.xwork2.ActionContext.container";
Map<String, Object> context;
public ActionContext(Map<String, Object> context)
{
this.context = context;
}
//... ...
public static void setContext(ActionContext context)
{
actionContext.set(context);
}
public static ActionContext getContext()
{
return (ActionContext)actionContext.get();
}
public void setContextMap(Map<String, Object> contextMap)
{
getContext().context = contextMap;
}
public Map<String, Object> getContextMap()
{
return this.context;
}
//... ...
public void setSession(Map<String, Object> session)
{
put("com.opensymphony.xwork2.ActionContext.session", session);
}
public Map<String, Object> getSession()
{
return (Map)get("com.opensymphony.xwork2.ActionContext.session");
}
//... ...
public Object get(String key)
{
return this.context.get(key);
}
public void put(String key, Object value)
{
this.context.put(key, value);
}
}
源码清晰的说明了我们编程中再熟悉不过的一行代码: ActionContext ctx = ActionContext.getContext();,原来我们所取得的ctx来自于 ThreadLocal 啊!熟悉 ThreadLocal 的朋友都知道它是与当前线程绑定的,而且是我们Java中处理多线程问题的一种重要方式。我们再看,类中有个 Map 类型的变量 context ,其实,它才是前面我们提到的真正意义上的“容器”,用来存放 Action 在执行时所需要的那些数据。
到这里,他最初的那个问题已经很了然了。但是,他紧接着又一个疑惑提出来了:“那既然每个请求处理线程都有自己的 ActionContext ,那里面的那些数据是什么时候放进去的呢”?
这次我给他的建议是,动脑筋,用源码验证。既然 ActionContext 存放有 HttpServletRequest 及其中的参数,既然 ActionContext 贯穿于整个请求处理过程,那就从struts2请求处理的入口(过滤器 StrutsPrepareAndExecuteFilter )找,源码:
public class StrutsPrepareAndExecuteFilter implements StrutsStatics, Filter
{
// ... ...
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException
{
HttpServletRequest request = (HttpServletRequest)req;
HttpServletResponse response = (HttpServletResponse)res;
try
{
this.prepare.setEncodingAndLocale(request, response);
this.prepare.createActionContext(request, response);//就是在这里进行创建并初始化ActionContext实例
this.prepare.assignDispatcherToThread();
if ((this.excludedPatterns != null) && (this.prepare.isUrlExcluded(request, this.excludedPatterns))) {
chain.doFilter(request, response);
} else {
request = this.prepare.wrapRequest(request);
ActionMapping mapping = this.prepare.findActionMapping(request, response, true);
if (mapping == null) {
boolean handled = this.execute.executeStaticResourceRequest(request, response);
if (!handled)
chain.doFilter(request, response);
}
else {
this.execute.executeAction(request, response, mapping);
}
}
} finally {
this.prepare.cleanupRequest(request);
}
}
//... ...
}
再找到 prepare 对应的类 PrepareOperations ,查看方法 createActionContext () ,就一目了然了。
对于 ServletActionContext 作为 ActionContext 一个直接子类,原理也是类似的,感兴趣的朋友可以看一下。
ActionContext实现原理的更多相关文章
- 菜鸟学Struts2——Struts工作原理
在完成Struts2的HelloWorld后,对Struts2的工作原理进行学习.Struts2框架可以按照模块来划分为Servlet Filters,Struts核心模块,拦截器和用户实现部分,其中 ...
- Web APi之过滤器执行过程原理解析【二】(十一)
前言 上一节我们详细讲解了过滤器的创建过程以及粗略的介绍了五种过滤器,用此五种过滤器对实现对执行Action方法各个时期的拦截非常重要.这一节我们简单将讲述在Action方法上.控制器上.全局上以及授 ...
- Web APi之过滤器创建过程原理解析【一】(十)
前言 Web API的简单流程就是从请求到执行到Action并最终作出响应,但是在这个过程有一把[筛子],那就是过滤器Filter,在从请求到Action这整个流程中使用Filter来进行相应的处理从 ...
- [转] valuestack,stackContext,ActionContext.之间的关系
三者之间的关系如下图所示: ActionContext 一次Action调用都会创建一个ActionContext 调用:ActionContext context = ActionContext ...
- Struts2(二):工作原理
struts可查看源码:https://github.com/apache/struts 在学习struts2之前,我先看了一些比较早版本对struts2的工作原理相关的介绍,顺便抄写过来,用来帮助自 ...
- 深入研究Struts2(一)---Struts2是什么?它的工作原理是什么?
本文绝对原创, 欢迎转载, 但是转载请记得注明文章出处:http://blog.csdn.net/izard999/article/details/39891281 近4年都在从事Android方 面 ...
- valuestack,stackContext,ActionContext.之间的关系
者之间的关系如下图所示: relation ActionContext 一次Action调用都会创建一个ActionContext 调用:ActionContext context = ActionC ...
- 剖析SSH核心原理(一)
在我前面的文章中,也试图总结过SSH,见 http://blog.csdn.net/shan9liang/article/details/8803989 ,随着知识的积累,总感觉以前说得比较笼统, ...
- strut2的原理
Struts2 在项目中用到的核心是拦截器interceptor,OGNL(Object Graph navigation Language)对象图导航语言(用来操作ValueStack里面的数据), ...
随机推荐
- 安装和配置jenkins
1.首先准备java环境,安装JDK 2.下载jenkins至Linux服务器 sudo wget -O /etc/yum.repos.d/jenkins.repo http://pkg.jenkin ...
- [BZOJ3551]Peaks
[BZOJ3551]Peaks BZOJ luogu 建Kruskal重构树,点权为边权 按dfn序建出主席树 倍增找到能跳到的最浅的祖先 主席树查询一下 #include<bits/stdc+ ...
- 005-快捷键,host,查看版本
一.系统快捷键 设置 键盘--查看 shift+ctrl +print 区域截图至剪切版 ctrl+alt+箭头 切换工作区 自定义打开终端快捷键 设置->键盘->自定义:名称: ...
- Android学习资源网站大全
https://github.com/zhujun2730/Android-Learning-Resources 整理了一些 Android 的博客链接.学习资源网站.站在巨人的肩膀上,会看得更远.整 ...
- springboot 项目跨域问题 CORS
package com.example.demo.cors; import org.springframework.context.annotation.Bean; import org.spring ...
- Android开发问题:ActivityNotFoundException: Unable to find explicit activity class
http://blog.csdn.net/debuglog/article/details/7236013 原因:AndroidManifest.xml未添加对应Activity配置. 解决办法:在A ...
- Android:日常学习笔记(5)——探究活动(2)
Android:日常学习笔记(5)——探究活动(2) 使用Intent在活动之间穿梭 什么是Intent Intent时Android程序中各组件之间进行交互的一种重要方式,他不仅可以指明当前组件想要 ...
- range基础
collapse这个方法是把结束位置抛弃掉,并不是简单的设置到开始位置. 结束位置被抛弃掉以后,只要没有给它重新设置位置,它就一直都会等 于开始位置.即使你修改了开始位置,结束位置还是会在修改后的开始 ...
- loadrunder之脚本篇——加密解密
密码加密 可以给密码加密,意在把结果字符串作为脚本的参数或者参数值.例如,完整可能有一个用户密码填写的表单,你想测试网站针对不同密码的反应,但是你又想保护密码的安全.Password Encoder允 ...
- iOS NSSet 学习 “无序数组” & 去重 案例
“NSSet,NSMutableSet,和NSCountedSet类声明编程接口对象的无序集合(散列存储:在内存中的存储位置不连续). 而NSArray,NSDictionary类声明编程接口对象的有 ...