【转】struts2的ActionInvocation分析(action调度者)
一个ActionInvocation实例代表一个action的执行状态,持有拦截器和将要执行的action的实例。
defaultActionInvocation是其默认实现。下面是定义在该类中的部分成员变量
public class DefaultActionInvocation implements ActionInvocation {
protected Object action;
protected ActionProxy proxy;
protected List<PreResultListener> preResultListeners;
protected ActionContext invocationContext;
protected Iterator<InterceptorMapping> interceptors;
protected String resultCode;
}
成员变量的含义:
action:用于接收一次请求中含有本次请求的处理逻辑的类。就是对应的struts.xml配置文件中的action对应的class类的对象。比如struts.xml中有<action name="login" class="com.xxx.LoginAction"></action>这个 配置片段。如果请求的action的name为login,那么defaultActionInvocation中的action成员变量将持有 一个com.xxx.LoginAction的实例。
proxy:action的执行环境,持有action执行所需的所有信息。
preResultListeners:一个监听器集合。这些监听器会在action执行完毕且Result执行之前调用。
invocationContext:action执行的环境,包含action执行需要的session,parameters,locale等 信息。
interceptors:ActionInvocation的重要的部分。包含了action执行过程中的所有拦截器,用于对action 进行预处理和后处理。拦截器的调用方式采用责任链模式,和Servlet中的过滤器的执行过程相似。
resultCode:action调用execute等方法处理完相应的逻辑后的返回值。比如success,login等。
下面分析defaultActionInvocation中的重要方法:invokeActionOnly,invokeAction和invoke方法
首先是invokeActionOnly方法,如下
public String invokeActionOnly() throws Exception {
return invokeAction(getAction(), proxy.getConfig());
}
该方法先通过getAction方法获取实际请求的action实例,并通过proxy获取构建ActionProxy对象的
ActionConfig实例。ActionConfig包含了一个action在struts.xml文件中的相关的配置信息。
接着是invokeAction方法,该方法只保留了源码中的一些关键部分,并不是完整的
protected String invokeAction(Object action, ActionConfig actionConfig) throws Exception { //通过getMethod获取在action配置文件中配置的要执行的方法
String methodName = proxy.getMethod(); try {
boolean methodCalled = false;
Object methodResult = null;
Method method = null;
try {
//getAction方法获取实际的action对象,然后获得它的
//Class对象,在通过getMethod方法,以反射的方式获得
//将要执行的方法
method = getAction().getClass().getMethod(methodName, EMPTY_CLASS_ARRAY); } catch (NoSuchMethodException e) {
try {
String altMethodName = "do" + methodName.substring(0, 1).toUpperCase() + methodName.substring(1);
method = getAction().getClass().getMethod(altMethodName, EMPTY_CLASS_ARRAY);
} catch (NoSuchMethodException e1) {
...
}
}
}
//如果该方法还未执行过,那么通过反射调用该方法
if (!methodCalled) {
methodResult = method.invoke(action, new Object[0]);
}
...
}
最后是最重要的invoke方法,保留了完整的代码,并加入了自己的理解注释(责任链模式)。如下
public String invoke() throws Exception {
String profileKey = "invoke: ";
try {
UtilTimerStack.push(profileKey); if (executed) {
throw new IllegalStateException("Action has already executed");
} //当前还有拦截器,则取出拦截器执行intercept方法
if (interceptors.hasNext()) {
//取出当前要执行的拦截器
final InterceptorMapping interceptor = (InterceptorMapping) interceptors.next();
String interceptorMsg = "interceptor: " + interceptor.getName();
UtilTimerStack.push(interceptorMsg);
try {
//执行拦截方法intercept,回去返回结果。传入DefaultActionInvocation.this
//参数是因为拦截器本身会调用ActionInvocation的invoke方法,因为实际类型是
//defaultActionInvocation,根据多态性,执行流程又会回到
//defaultActionInvocation的invoke方法,因为是同一个defaultActionInvocation
//那么就会取之前拦截器的下一个拦截器继续执行intercept方法
resultCode = interceptor.getInterceptor().intercept(DefaultActionInvocation.this); } finally {
UtilTimerStack.pop(interceptorMsg);
}
} else { //当前没有拦截器,那么调用请求的action中的处理方法
resultCode = invokeActionOnly();
} //PreResultListener会在action执行完后,Result执行之前执行,且只
//执行一次。使用了一个boolean类型的标志,若没有执行,则执行这些
//监听器。因为是在同一个ActionInvocation的实例中,所以当executed
//成员变量变为true后,之后的if判断通不过,就不在执行了
if (!executed) {
if (preResultListeners != null) {
for (Object preResultListener : preResultListeners) {
PreResultListener listener = (PreResultListener) preResultListener;
String _profileKey = "preResultListener: ";
try {
UtilTimerStack.push(_profileKey);
listener.beforeResult(this, resultCode);
}
finally {
UtilTimerStack.pop(_profileKey);
}
}
} //可以看到PreResultListener的执行是在action执行后,Result执行前
if (proxy.getExecuteResult()) {
executeResult();
}
executed = true; //设置为true,保证PreResultListener不再执行
} return resultCode; //返回action执行完毕后的返回值
}
finally {
UtilTimerStack.pop(profileKey);
}
}
Action的调用者使用以上三个方法来完成请求的拦截和相应的action方法的执行。成员变量中最重要的就是表示实际Action类的action和拦截器的集合interceptors。interceptors持有所有对action请求进行拦截的拦截器引用,而action成员变量持有对请求进行实际处理的类的对象。
转载:https://blog.csdn.net/ikaraide/article/details/17719823。
【转】struts2的ActionInvocation分析(action调度者)的更多相关文章
- Struts2 源码分析——Action代理类的工作
章节简言 上一章笔者讲到关于如何加载配置文件里面的package元素节点信息.相信读者到这里心里面对struts2在启动的时候加载相关的信息有了一定的了解和认识.而本章将讲到关于struts2启动成功 ...
- Struts2 源码分析——DefaultActionInvocation类的执行action
本章简言 上一章讲到关于拦截器的机制的知识点,让我们对拦截器有了一定的认识.我们也清楚的知道在执行用户action类实例之前,struts2会先去执行当前action类对应的拦截器.而关于在哪里执行a ...
- Struts2 源码分析——拦截器的机制
本章简言 上一章讲到关于action代理类的工作.即是如何去找对应的action配置信息,并执行action类的实例.而这一章笔者将讲到在执行action需要用到的拦截器.为什么要讲拦截器呢?可以这样 ...
- Struts2 源码分析——调结者(Dispatcher)之执行action
章节简言 上一章笔者写关于Dispatcher类如何处理接受来的request请求.当然读者们也知道他并非正真的执行action操作.他只是在执行action操作之前的准备工作.那么谁才是正真的执行a ...
- Struts2源代码解读之Action调用
对于Struts2源代码的分析已经有些时日了,虽然网上有很多解读代码,不过自己还是写一个放上来,供大家参考一下. 解读过程: 直接在action类中打断点(包括构造函数和待执行方法)进行debug调试 ...
- 源码分析——Action代理类的工作
Action代理类的新建 通过<Struts2 源码分析——调结者(Dispatcher)之执行action>章节我们知道执行action请求,最后会落到Dispatcher类的serv ...
- Struts2 源码分析——配置管理之PackageProvider接口
本章简言 上一章讲到关于ContainerProvider的知识.让我们知道struts2是如何注册相关的数据.也知道如何加载相关的配置信息.本章笔者将讲到如何加载配置文件里面的package元素节点 ...
- Struts2 源码分析——配置管理之ContainerProvider接口
本章简言 上一章笔者讲到关于Dispatcher类的执行action功能,知道了关于执行action需要用到的信息.而本章将会讲到的内容也跟Dispatcher类有关系.那就是配置管理中的Contai ...
- Struts2 源码分析——过滤器(Filter)
章节简言 上一章笔者试着建一个Hello world的例子.是一个空白的struts2例子.明白了运行struts2至少需要用到哪一些Jar包.而这一章笔者将根据前面章节(Struts2 源码分析—— ...
随机推荐
- Java面试题的个人总结
面试总结 第一轮:电话初面 第二轮:技能面谈[技能职位尽量避免多谈处理上的作业] 第三轮:高管复试 第四轮:HR终究供认 一面:首要供认对阿里的意向度(假定异地更会考虑对作业地址(杭州)的意向度!阿里 ...
- 第05组 Alpha冲刺(4/4)
第05组 Alpha冲刺(4/4) 队名:天码行空 组长博客连接 作业博客连接 团队燃尽图(共享): GitHub当日代码/文档签入记录展示(共享): 组员情况: 组员1:卢欢(组长) 过去两天完成了 ...
- python Qt5 实战(一)按钮颜色
工作中,工具用到了python Qt5,涉及到了按钮颜色,这里就做个总结.也顺便给要用这块的同仁抛出来一个砖头,把大牛引出来做个指导. 一般设置按钮的颜色有三种表达:如下所示:具体的怎么使用,估计要看 ...
- 理解Promise.all,Promise.all与Promise.race的区别,如何让Promise.all在rejected失败后依然返回resolved成功结果
壹 ❀ 引 我在 es6入门4--promise详解 这篇文章中有详细介绍Promise对象的用法,文章主题更偏向于对于Promise概念的理解与各方法基本使用介绍:而世上一个比较有趣的问题就是,即 ...
- 相关pycharm(进阶?)
记录今日发现 对于pycharm细节 注意:项目的位置可以自己定 这里的新建project,建议对python.exe 文件的选择使用自己安装的位置,如下图 create,你就有了一个解释器是你自己安 ...
- [IDA] 将连续的单个变量值修改为结构体
直接选中最上边的结构体,使用ALT+Q来进行修改.
- Core源码(四)IEnumerable
首先我们去core的源码中去找IEnumerable发现并没有,如下 Core中应该是直接使用.net中对IEnumerable的定义 自己实现迭代器 迭代器是通过IEnumerable和IEnume ...
- 关于EFCore线程内唯一
EntityFramework的线程内唯一 EntityFramework的线程内唯一是通过httpcontext来实现的 public static DbContext DbContext() { ...
- Python 内置函数补充匿名函数
Python3 匿名函数 定义一个函数与变量的定义非常相似,对于有名函数,必须通过变量名访问 def func(x,y,z=1): return x+y+z print(func(1,2,3)) 匿名 ...
- mysql 是否走索引问题
问题探讨 : 当一列包含null 值时, is null 和 is not null 查询是否走索引 当用 != 时是否走索引 当用in时是否走索引 结论:当 查询范围比较小时, 以上枚举的都走索 ...