从源代码分析modelDriven拦截器和params拦截器和拦截器prepare 和paramsPrepareParamsStack拦截器栈(让你的Struts2代码更简洁——如何培养框架设计能力
源代码文件:Web App Libraries/struts2-core-2.3.15.3.jar/struts-default.xml
拦截器modelDriven: <interceptor |
拦截器params: <interceptor |
拦截器prepare: <interceptor |
拦截器栈: <interceptor-stack <interceptor-ref <interceptor-ref <interceptor-ref <interceptor-ref <interceptor-ref <interceptor-ref <param </interceptor-ref> <interceptor-ref <interceptor-ref <interceptor-ref <interceptor-ref <interceptor-ref <interceptor-ref <interceptor-ref <interceptor-ref <param </interceptor-ref> <interceptor-ref <interceptor-ref <param </interceptor-ref> <interceptor-ref <param </interceptor-ref> </interceptor-stack> |
ModelDriven拦截器的作用:
当用户触发每一个请求时,ModelDriven拦截器将调用JavaBean对象的getModel()方法,并把返回值类型压入到ValueStack栈
Params拦截器的作用:
将表单的字段映射到ValueStack栈的栈顶对象的各个属性中。由于此时ValueStack栈的栈顶元素是刚被压入的模型(JavaBean)对象(先用到ModelDriven拦截器,才有这句话),所以该模型将被填充,假设每一个字段在模型里没有匹配的属性,Params拦截器将尝试ValueStack栈中的下一个对象。
PrepareInterceptor拦截器的作用:
u 若Action实现Preparable接口,则Action方法需实现prepare()方法
u PrepareInterceptor拦截器将调用prepare()方法、prepareActionMethodName()方法和prepareDoActionMethodName()方法
u PrepareInterceptor拦截器依据firstCallPrepareDo属性决定获取prepareActionMethodName、prepareDoActionNam的顺序。默认情况下先获取prepareDoActionName(),假设没有该方法,就寻找prepareDoActionMethodName()。
假设找到了相应的方法就调用该方法。
u PrepareInterceptor拦截器会依据alwaysInvokePrepare属性决定是否运行prepare()方法
paramsPrepareParamsStack拦截器栈的作用:(參考struts-default.xml配置文件的结构。就知道具体的含义了)。如今具体解析一下:
u paramsPrepareParamsStack从字面上理解来说。这里Stack的拦截器调用的顺序为:首先params,然后prepare,接下来modelDriven。最后在params
u Struts2.0的设计上要求modelDriven在params之前调用,而业务中prepare要负责准备model,准备model又须要參数,这就须要在prepare之前执行params拦截器设置相关參数,这个也就是创建paramsPrepareParamsStack的原因。
u 流程例如以下:
A. Params拦截器首先给action中的相关參数赋值。如id
B. Prepare拦截器运行prepare方法,prepare方法中会依据參数,如id,去调用业务逻辑,设置model对象
C. ModelDriver拦截器将model对象压入ValueStack,这里的model对象就是在prepare中创建的
D. Params拦截器再将參数赋值给model对象
E. Action的业务逻辑运行
请參考以下源码解析:(第一部分是PrepareInterceptor拦截器的操作流程)
package com.opensymphony.xwork2.interceptor; import com.opensymphony.xwork2.ActionInvocation; import com.opensymphony.xwork2.Preparable; import com.opensymphony.xwork2.util.logging.Logger; import com.opensymphony.xwork2.util.logging.LoggerFactory; import java.lang.reflect.InvocationTargetException; public private private private private private public this.alwaysInvokePrepare = Boolean.parseBoolean(alwaysInvokePrepare); } public this.firstCallPrepareDo = Boolean.parseBoolean(firstCallPrepareDo); } @Override public String doIntercept(ActionInvocation invocation) //获取Action对象 Object action = invocation.getAction(); //推断Action是否实现了preparable接口 if (action try { String[] prefixes; //依据当前拦截器的 firstCallPrepareDo(默觉得 false) if (firstCallPrepareDo) { prefixes = new String[] {ALT_PREPARE_PREFIX, } else { prefixes = new String[] {PREPARE_PREFIX, } //若为 false, //调用前缀方法. PrefixMethodInvocationUtil.invokePrefixMethod(invocation, prefixes); } catch (InvocationTargetException e) { Throwable cause = e.getCause(); if (cause throw (Exception) cause; } else throw (Error) cause; } else { throw e; } } //依据当前拦截器的 alwaysInvokePrepare(默认是 true) if (alwaysInvokePrepare) { ((Preparable) action).prepare(); } } return invocation.invoke(); } } |
PrefixMethodInvocationUtil.invokePrefixMethod(invocation, prefixes) 方法: |
package com.opensymphony.xwork2.interceptor; import com.opensymphony.xwork2.ActionInvocation; import com.opensymphony.xwork2.util.logging.Logger; import com.opensymphony.xwork2.util.logging.LoggerFactory; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public private private private public //获取 Action Object action = actionInvocation.getAction(); //获取要调用的 Action String methodName = actionInvocation.getProxy().getMethod(); if (methodName == // if null returns (possible according to the docs), use the default execute methodName = DEFAULT_INVOCATION_METHODNAME; } //获取前缀方法 Method method = getPrefixedMethod(prefixes, methodName, action); //若方法不为 null, if (method != method.invoke(action, new Object[0]); } } public assert(prefixes != //把方法的首字母变为大写 String capitalizedMethodName =capitalizeMethodName(methodName); //遍历前缀数组 for (String prefixe : prefixes) { String prefixedMethodName = prefixe + capitalizedMethodName; //通过拼接的方式, try { //利用反射获从 action return action.getClass().getMethod(prefixedMethodName, } catch (NoSuchMethodException e) { // hmm -- OK, try next prefix if (LOG.isDebugEnabled()) { LOG.debug("cannot find method [#0] in action [#1]", prefixedMethodName, action.toString()); } } } return } public assert(methodName != return methodName.substring(0, 1).toUpperCase() + methodName.substring(1); } } |
第二部分(ModelDriver拦截器的源码解析)
package com.opensymphony.xwork2.interceptor; import com.opensymphony.xwork2.ActionInvocation; import com.opensymphony.xwork2.ModelDriven; import com.opensymphony.xwork2.util.CompoundRoot; import com.opensymphony.xwork2.util.ValueStack; public protected public this.refreshModelBeforeResult = val; } @Override public String intercept(ActionInvocation invocation) //获取 Action //public class EmployeeAction implements RequestAware, ModelDriven<Employee> Object action = invocation.getAction(); //推断 action if (action //强制转换为 ModelDriven ModelDriven modelDriven = (ModelDriven) action; //获取值栈 ValueStack stack = invocation.getStack(); //调用 ModelDriven //即调用 EmployeeAction /* public Employee getModel() { employee = new Employee(); return employee; } */ Object model = modelDriven.getModel(); if (model != //把 getModel() stack.push(model); } if (refreshModelBeforeResult) { invocation.addPreResultListener(new RefreshModelBeforeResult(modelDriven, model)); } } return invocation.invoke(); } /** * Refreshes the model instance on the value stack, if it has changed */ protected private Object protected ModelDriven public RefreshModelBeforeResult(ModelDriven action, Object model) { this.originalModel = model; this.action = action; } public ValueStack stack = invocation.getStack(); CompoundRoot root = stack.getRoot(); boolean needsRefresh = Object newModel = action.getModel(); // Check to see if the new model instance is already on the stack for (Object item : root) { if (item.equals(newModel)) { needsRefresh = false; } } // Add the new model on the stack if (needsRefresh) { // Clear off the old model instance if (originalModel != root.remove(originalModel); } if (newModel != stack.push(newModel); } } } } } |
细节凝视:
细节一:运行 ParametersInterceptor 的 intercept 方法: 把请求參数的值赋给栈顶对象相应的属性. 若栈顶对象没有相应的属性, 则查询值栈中下一个对象相应的属性...
细节二:getModel 方法不能提供下面实现. 的确会返回一个 Employee 对象到值栈的栈顶. 但当前 Action 的 employee 成员变量却是 null.
@Override public return } |
版权声明:本文博客原创文章,博客,未经同意,不得转载。
从源代码分析modelDriven拦截器和params拦截器和拦截器prepare 和paramsPrepareParamsStack拦截器栈(让你的Struts2代码更简洁——如何培养框架设计能力的更多相关文章
- Android AsyncTask 源代码分析
AsyncTask源代码分析 public abstract class AsyncTask<Params, Progress, Result> { //日志TAG private sta ...
- struts2 paramsPrepareParamsStack拦截器简化代码(源码分析)
目录 一.在讲 paramsPrepareParamsStack 之前,先看一个增删改查的例子. 1. Dao.java准备数据和提供增删改查 2. Employee.java 为model 3. E ...
- SDL2源代码分析6:复制到渲染器(SDL_RenderCopy())
===================================================== SDL源代码分析系列文章列表: SDL2源代码分析1:初始化(SDL_Init()) SDL ...
- SDL2源代码分析3:渲染器(SDL_Renderer)
===================================================== SDL源代码分析系列文章列表: SDL2源代码分析1:初始化(SDL_Init()) SDL ...
- XBMC源代码分析 7:视频播放器(dvdplayer)-输入流(以libRTMP为例)
前文分析了XBMC的基本结构: XBMC源代码分析 1:整体结构以及编译方法 XBMC源代码分析 2:Addons(皮肤Skin) XBMC源代码分析 3:核心部分(core)-综述 XBMC源代码分 ...
- XBMC源代码分析 6:视频播放器(dvdplayer)-文件头(以ffmpeg为例)
XBMC分析系列文章: XBMC源代码分析 1:整体结构以及编译方法 XBMC源代码分析 2:Addons(皮肤Skin) XBMC源代码分析 3:核心部分(core)-综述 XBMC源代码分析 4: ...
- XBMC源代码分析 4:视频播放器(dvdplayer)-解码器(以ffmpeg为例)
XBMC分析系列文章: XBMC源代码分析 1:整体结构以及编译方法 XBMC源代码分析 2:Addons(皮肤Skin) XBMC源代码分析 3:核心部分(core)-综述 本文我们分析XBMC中视 ...
- 使用 paramsPrepareParamsStack 拦截器栈后的运行流程
2. 使用 paramsPrepareParamsStack 拦截器栈后的运行流程 1). paramsPrepareParamsStack 和 defaultStack 一样都是拦截器栈. 而 st ...
- 【Java EE 学习 69 上】【struts2】【paramsPrepareParamsStack拦截器栈解决model对象和属性赋值冲突问题】
昨天有同学问我问题,他告诉我他的Action中的一个属性明明提供了get/set方法,但是在方法中却获取不到表单中传递过来的值.代码如下(简化后的代码) public class UserAction ...
随机推荐
- margin 还能够被缩回
<p><strong>话:</strong>的肥沃和收获而被估价的.才干也是土地,只是它生产的不是粮食,而是真理.假设仅仅能滋生瞑想和幻想的话,即使再大的才干也仅仅 ...
- Deploy 11.2.0.3 RAC+DG on Windows 2008 R2 Step by Step
环境规划: 节点1: tc1 192.168.56.101 内存:2G 节点2: tc2 192.168.56.102 内存:2G 物理备库:tcdg192.168.56.108内存:1.5G 操作系 ...
- HibernateReview Day1 - Introduction
Hibernate已经学过去大概有半个月了,然后默默的忘掉了……所谓Practice makes perfect. 我尽力重新拾起来. 1.什么是ORM 在介绍Hibernate之前,我们先学习下OR ...
- 配置jndi服务,javax.naming.NamingException的四种情况
1.当jndi服务没有启动,或者jndi服务的属性没有设置正确,抛出如下异常: javax.naming.CommunicationException: Can't find SerialContex ...
- Hibernate4.3.9Final常见问题汇总
hibernate4下一个可用的hibernate.properties: jdbc.driverClassName=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql ...
- facade pattern
外观模式是一种使用频率非常高的设计模式,它通过引入一个外观角色来简化客户端与子系统之间的交互,为复杂的子系统调用提供一个统一的入口,使子系统与客户端的耦合度降低,且客户端调用非常方便.外观模式并不给系 ...
- SpringMVC单文件上传、多文件上传、文件列表显示、文件下载(转)
林炳文Evankaka原创作品.转载请注明出处http://blog.csdn.net/evankaka 本文详细讲解了SpringMVC实例单文件上传.多文件上传.文件列表显示.文件下载. 本文工程 ...
- 找呀志_java网络编程(5)TCP和udp差额
1.TCP定向链接,尽管该网络的不稳定性质,所述不安全确定多少次握手不能保证连接的可靠性.但TCP的三次握手至少(事实上确保了相当大的程度)以确保连接的可靠性; 和UDP不面向连接的,UDP前传送的数 ...
- 15一个NoSql数据库
随着因特网web2.0该网站的兴起.非关系型数据库,现在已经成为一个非常受欢迎的新领域.非关系数据库产品的发展非常迅速.而在处理传统的关系数据库web2.0现场.特别是大规模,高并发SNS类型web2 ...
- 【Unity技能】做一个简单的NPC
1. 写在前面 前几天我看到cgcookie一个教程.学习了下怎么依据已有人物模型制作一个仿版的NPC人物.感觉挺好玩的,整理一下放到博客里! 先看一下教程里面的终于效果. 是不是非常像个幽灵~ 以下 ...