struts2 18拦截器详解(七)
ChainingInterceptor
该拦截器处于defaultStack第六的位置,其主要功能是复制值栈(ValueStack)中的所有对象的所有属性到当前正在执行的Action中,如果说ValueStack中没有任何对象的话,该拦截器不会干任何事情,看到这个拦截器的名称,大家应该会想到有一种chain类型的Result,该拦截器主要就是针对chain类型Result起作用的,因为我们有可能在chain链后面的Action用到前面Action的属性,所以struts2提供了该拦截器来实现这个功能。当然我们也可以让chain链中的某个Action属性不复制到正在执行的Action中,只要chain链中的Action实现com.opensymphony.xwork2.Unchainable接口,这个Action中的属性就不会复制到当前正在执行的Action中了。下面我们看一个该拦截器的源码:
@Override
public String intercept(ActionInvocation invocation) throws Exception {
ValueStack stack = invocation.getStack();//获取值栈
CompoundRoot root = stack.getRoot();//获取值栈中的root对象,其实就是一个List
//如果值栈中有对象
if (root.size() > 1) {
//把值栈中的对象引用复制到一个List中,目的是不破坏值栈中的对象
List<CompoundRoot> list = new ArrayList<CompoundRoot>(root);
list.remove(0);//移除第一个元素,即当前正在执行的Action对象
//然后将该List中对象反序,这样复制到当前Action中的属性是chain链中最后面Action的属性
Collections.reverse(list);
//获取ActionContext对象内部的contextMap对象,其实就是OgnlContext对象
Map<String, Object> ctxMap = invocation.getInvocationContext().getContextMap();
Iterator<CompoundRoot> iterator = list.iterator();
int index = 1; // starts with 1, 0 has been removed
while (iterator.hasNext()) {//迭代
index = index + 1;
Object o = iterator.next();
if (o != null) {
if (!(o instanceof Unchainable)) {//如果当前被迭代的对象没有实现Unchainable接口,则要进行属性复制
reflectionProvider.copy(o, invocation.getAction(), ctxMap, excludes, includes);//复制属性
}
}
else {
LOG.warn("compound root element at index "+index+" is null");
}
}
} return invocation.invoke();
}
注释已经写得清楚了,下面以一段Action配置来进一步讲解,配置如下:
<action name="test" class="com.xtayfjpk.action.TestAction">
<result name="chain" type="chain">chain</result>
</action>
<action name="chain" class="com.xtayfjpk.action.ChainAction">
<result name="success">/WEB-INF/page/message.jsp</result>
</action>
这里test action的Result类型为chain,指向了chain action,当执行TestAction时,值栈中就两个对象,第一个是TestAction自己,第二个是一个com.opensymphony.xwork2.DefaultTextProvider对象,由于当前Action被移除不会参数迭代,而DefaultTextProvider实现了Unchainable接口,所以不会执行reflectionProvider.copy方法,也就没有属性的复制。
当执行ChainAction到该拦截器时,值栈中有三个对象,第一个是ChainAction自己,第二个是TestAction对象,第三个是DefaultTextProvider,
根据上面的逻辑,就会把TestAction的所有属性复制给ChainAction对象,如果说ChainAction返回的又是chain类型的Result,则又会把ChainAction和TestAction的所有属性复制给下一个Action,依此类推......
现在我们看一下这句属性复制代码:reflectionProvider.copy(o, invocation.getAction(), ctxMap, excludes, includes);copy方法的第一个参数就是值栈中要被复制属性的对象,第二个参数是当前正在执行的Action,第三个参数是OgnlContext对象,第四、五个参数excludes与includes是一个属性名称集合,excludes表示不需要被复制的属性集合,includes表示要被复制的属性集合,下面是copy方法源码:
public void copy(Object from, Object to, Map<String, Object> context,
Collection<String> exclusions, Collection<String> inclusions) {
ognlUtil.copy(from, to, context, exclusions, inclusions);
}
它调用了ognlUtil.copy方法,我们进入该方法:
public void copy(Object from, Object to, Map<String, Object> context, Collection<String> exclusions, Collection<String> inclusions) {
//省略...
PropertyDescriptor[] fromPds;
PropertyDescriptor[] toPds;
try {
fromPds = getPropertyDescriptors(from);//获取源对象(要被复制属性的对象)的属性描述符
toPds = getPropertyDescriptors(to);//获目标对象(当前正在执行的Action对象)的属性描述符
} catch (IntrospectionException e) {
LOG.error("An error occured", e);
return;
}
Map<String, PropertyDescriptor> toPdHash = new HashMap<String, PropertyDescriptor>();
for (PropertyDescriptor toPd : toPds) {
toPdHash.put(toPd.getName(), toPd);//将目标对象属性描述符放到一个HashMap中
}
//迭代获取源对象属性描述符
for (PropertyDescriptor fromPd : fromPds) {
if (fromPd.getReadMethod() != null) {//当前属性的读方法不为空
boolean copy = true;
if (exclusions != null && exclusions.contains(fromPd.getName())) {
//如果当前属性包含在exclusions集合中则不复制
copy = false;
} else if (inclusions != null && !inclusions.contains(fromPd.getName())) {
//如果配置了inclusions,而当前属性又不包含在inclusions集合中则不复制
//如果没有配置inclusions,则只要不包含在exclusions就会复制
copy = false;
}
if (copy == true) {//如果当前属性需要复制
PropertyDescriptor toPd = toPdHash.get(fromPd.getName());//获取目标对象相应的属性描述符
if ((toPd != null) && (toPd.getWriteMethod() != null)) {//如果属性描述符存在且其写方法不为空则进行复制
try {
Object expr = compile(fromPd.getName());
Object value = Ognl.getValue(expr, contextFrom, from);
Ognl.setValue(expr, contextTo, to, value);//真正复制属性的代码
} catch (OgnlException e) {
// ignore, this is OK
}
}
}
}
}
}
至此,该拦截器要复制哪些属性,要复制哪些对象的属性,以及复制属性的具体规则已经讲解完毕了,最后一句:Ognl.setValue(expr, contextTo, to, value);
真正复制属性的代码已经涉及到OGNL内部的实现机制,这是很复杂的,但对于理解该拦截器来说不是很重要,这里就不说了,有兴趣的可自行研究。
现在回到intercept方法,当属性复制完成后调用invocation.invoke();继续执行下一个拦截器......
struts2 18拦截器详解(七)的更多相关文章
- struts2 18拦截器详解(十)
ModelDrivenInterceptor 该拦截器处于defaultStack中的第九的位置,在ScopedModelDrivenInterceptor拦截器之后,要使该拦截器有效的话,Actio ...
- struts2 18拦截器详解(九)
ScopedModelDrivenInterceptor 该拦截器处于defaultStack第八的位置,其主要功能是从指定的作用域内检索相应的model设置到Action中,该类中有三个相关的属性: ...
- struts2 18拦截器详解(五)
I18nInterceptor 该拦截器处理defaultStack第四的位置,是用来方便国际化的,如果说我们的一个Web项目要支持国际化的话,通常的做法是给定一个下拉框列出所支持的语言,当用户选择了 ...
- 通俗易懂之SpringMVC&Struts2前端拦截器详解
直接进入主题吧!一,配置Struts2的拦截器分两步走1配置对应的拦截器类:2在配置文件Struts.xml中进行配置拦截器同时在Strust2中配置拦截器类有三种方法1实现Interceptor接口 ...
- struts2内置拦截器和自定义拦截器详解(附源码)
一.Struts2内置拦截器 Struts2中内置类许多的拦截器,它们提供了许多Struts2的核心功能和可选的高级特 性.这些内置的拦截器在struts-default.xml中配置.只有配置了拦截 ...
- Struts2 之 modelDriven & prepare 拦截器详解
struts2 ModelDriven & Prepareable 拦截器 前面对于 Struts2 的开发环境的搭建.配置文件以及 Struts2 的值栈都已经进行过叙述了!这次博文我们讲解 ...
- Struts2拦截器详解
一.Struts2拦截器原理: Struts2拦截器的实现原理相对简单,当请求struts2的action时,Struts 2会查找配置文件,并根据其配置实例化相对的 拦截器对象,然后串成一个列 ...
- Struts2中的拦截器详解
exception:异常拦截器,拦截异常aliasservletConfig18nprepare:预备拦截器,这个拦截器就是为了ModelDriven准备对象的,若Action类实现了preparab ...
- [转]SpringMVC拦截器详解[附带源码分析]
目录 前言 重要接口及类介绍 源码分析 拦截器的配置 编写自定义的拦截器 总结 前言 SpringMVC是目前主流的Web MVC框架之一. 如果有同学对它不熟悉,那么请参考它的入门blog:ht ...
随机推荐
- 安装sqlserver2008r2 服务器配置,服务帐户配置出错,提示Sql server服务指定的凭据无效
win+X 点击运行 重置帐户密码使得sql server2008 的服务帐户名,密码与系统设置的Administrator名与密码一致,则可. 上图中有一项reporting的名字不同,该名字为自动 ...
- Fiddler-008-简单模拟性能测试
通过 Fiddler 可以简单的模拟性能测试的并发测试,此方法非常的简单,直接讲述如何使用,敬请参阅! 首先我们要获取需要并发的 HTTP请求,此操作非常简单,则在此不再赘述.获取到响应的 HTTP请 ...
- Download InstallShield Limited Edition for Visual Studio 地址
http://learn.flexerasoftware.com/content/IS-EVAL-InstallShield-Limited-Edition-Visual-Studio?lang=10 ...
- 关于OC语法的公开和私有的讨论
关于OC语法的公开和私有的讨论 OC语法中,类的.h文件向外面暴露类的功能/方法接口,其中定义的属性/方法/协议/类别/类扩展都属于公开的,但实例变量要看限定词(@protected/@public/ ...
- shell中如何判断某一命令是否存在
参考: http://www.cnblogs.com/tuzkee/p/3755230.html https://segmentfault.com/q/1010000000156870 http:// ...
- 转:VS中的路径宏 vc++中OutDir、ProjectDir、SolutionDir各种路径
http://www.cnblogs.com/lidabo/archive/2012/05/29/2524170.html
- runtime获取类名,遍历变量,遍历对象,遍历方法
- iOS支付后默认关注公众号
1.这个是微信内部的功能,不对外公开,需要商务洽谈.跟技术无关. 2.同时金额少于1块的也不会有提示关注显示. 3.关注过的不会默认再次关注,但是仍然有选项可以选择.
- Oracle 11g RAC 第二节点root.sh执行失败后再次执行root.sh
Oracle 11g RAC 第二节点root.sh执行失败后再次执行root.sh前,要先清除之前的crs配置信息 # /u01/app/11.2.0/grid/crs/install/rootcr ...
- Oracle sqlldr导入导出txt数据文件详解
一.sqlldr导入txt 1.预备 a).txt文件 这里要保存成无签名的UTF-8 b).oracle建表 2.编写控制文件input_test.ctl LOAD DATA CHARACTERSE ...