从源代码分析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 ...
随机推荐
- [欧拉回路] hdu 3018 Ant Trip
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=3018 Ant Trip Time Limit: 2000/1000 MS (Java/Others) ...
- java该HashTable,HashMap和HashSet
同一时候我们也对HashSet和HashMap的核心方法hashcode进行了具体解释,见<探索equals()和hashCode()方法>. 万事俱备,那么以下我们就对基于hash算法的 ...
- hbase列表排序
hbase都是依照字典序进行排序的,也就是降序,在页面的表现就是最早的数据(rowkey最小的)排在前面. 眼下的解决方式是:给主键添加一个外键关联表.外键的生成规则是 400000000000-主键 ...
- HTTP/1.1
HTTP真的很简单 原文:HTTP Made Really Easy因为我本身网络基础就很差,所以看到这篇文章一方面是学习网络知识,另一方面为了锻炼我蹩脚的英语水平,文中如有错误,欢迎浏览指正! ...
- IAR FOR ARM 各版本号,须要的大家能够收藏了
首先感谢大家的支持与关注,如今应该又一次编辑这篇文章了,这篇文章是非常久曾经不知在什么地方Copy过来的, 非常多问题不知怎么解决,如今我用的是KEIL for arm. 用过Keil和IAR,个人感 ...
- [Ext.Net]GridPanel之Access数据库分页显示
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.D ...
- java自学者的福音
谈到自学对于程序员来说并不陌生,自从我们离开校门就开始了自学之路.这一路上绝大部分都是 百步止于九十 步, 不是因为他们不够坚持,而是没有找到学习的方法和资源.当然这一路上我也走得很辛苦,刚毕业后自学 ...
- 检验身份证的正确性(Golang版本)
// CheckID_card project main.go package main /* * ai -> a1 , a2, a3, a4, a5, a6... a17 (a18 是校验码) ...
- Java引用类型变量
Java引用类型变量 1.编译时类型:由声明该变量时使用的类型决定 2.执行时类型:由实际赋给该变量的对象决定 类型不一致的假设编译时类型和执行,可能会出现多态性 版权声明:本文博主原创文章.博 ...
- ECG信号读出,检测QRS,P,T 波(小波去噪,并根据检测),基于BP辨识的神经网络
这学期的课程选择神经网络.最后的作业处理ECG信号,并利用神经网络识别. 1 ECG引进和阅读ECG信号 1)ECG介绍 详细ECG背景应用就不介绍了,大家能够參考百度 谷歌.仅仅是简单说下ECG ...