从源代码分析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 ...
随机推荐
- Android 上实现非root的 Traceroute -- 非Root权限下移植可运行二进制文件 脚本文件
作者 : 万境绝尘 转载请著名出处 : http://blog.csdn.net/shulianghan/article/details/36438365 演示样例代码下载 : -- CSDN : h ...
- 通信协议:HTTP、TCP、UDP(转)
原文出处: 碧雪轩的博客 TCP HTTP UDP: 都是通信协议,也就是通信时所遵守的规则,只有双方按照这个规则“说话”,对方才能理解或为之服务. TCP HTTP UDP三者的关系 ...
- 集成学习---bagging and boosting
作为集成学习的二个方法,其实bagging和boosting的实现比较容易理解,但是理论证明比较费力.下面首先介绍这两种方法. 所谓的集成学习,就是用多重或多个弱分类器结合为一个强分类器,从而达到提升 ...
- Atitit.软件的仪表板(8)--os子系统--监控资源使用情况
Atitit.软件的仪表板(8)--os系统--资源占用监測 CPU使用 内存使用 磁盘队列 任务管理器 网络速度 插件列表( 资源管理器插件,浏览器插件,360optim) 启动项管理 (350) ...
- Spark 1.0.0 横空出世 Spark on Yarn 部署(Hadoop 2.4)
就在昨天,北京时间5月30日20点多.Spark 1.0.0最终公布了:Spark 1.0.0 released 依据官网描写叙述,Spark 1.0.0支持SQL编写:Spark SQL Progr ...
- CSS预处理器——Sass、LESS和Stylus实践
CSS(Cascading Style Sheet)被译为级联样式表,做为一名前端从业人员来说,这个专业名词并不陌生,在行业中通常称之为“风格样式表(Style Sheet)”,它主要是用来进行网页风 ...
- Windows 8 应用开发 - 应用栏
原文:Windows 8 应用开发 - 应用栏 通过应用栏(AppBar)可以在需要时向用户显示各种应用命令.应用栏提供与用户当前页面或当前选定的内容相关的各种命令.默认情况下,应用栏处于隐 ...
- mysql table is marked as crashed and last (automatic?) repair failed
1.同事的服务器在mysqldump备份的时候报错了 这个原因是myisam的表数据太多,在某个时刻, 存放数据的这个MyISAM表数据急速长大. 比如一些log表, 当硬盘写满了.这个时候还在继续写 ...
- HTML5 Storage API
原文:HTML5 Storage API Web Storage是HTML5引入的一个非常重要的功能,可以在客户端本地存储数据,类似HTML4的cookie,但可实现功能要比cookie强大的多. 在 ...
- 解决win10 iot VS编程出现的无法引用错误
使用NuGet安装 Microsoft.NETCore 5.0 安装 Microsoft.NETCore