DefaultActionInvocation类的执行action
| DefaultActionInvocation类的执行action | 
上一章里面有提到过DefaultActionInvocation类的invoke方法里面的invokeActionOnly方法。没有错!当所有拦截器前半部分执行结束之后,就会去执行invokeActionOnly方法。这个方法就是执行action类实例的入口。而invokeActionOnly方法实际是去调用本身类的invokeAction方法。看一下代码就知道了。
DefaultActionInvocation类:
1 public String invokeActionOnly() throws Exception {
2         return invokeAction(getAction(), proxy.getConfig());
3     }
代码里面getAction方法就是获得action类实例。即是跟《Struts2 源码分析——Action代理类的工作》章节里面讲到的createAction方法有关。当程序执行到这里的时候,createAction方法已经新建好了action类实例。不清楚读者请到这章去看一下。让我们看一下invokeAction方法的源码吧。

 1 protected String invokeAction(Object action, ActionConfig actionConfig) throws Exception {
 2         String methodName = proxy.getMethod();//获得要执行的方法名。
 3
 4         LOG.debug("Executing action method = {}", methodName);
 5
 6         String timerKey = "invokeAction: " + proxy.getActionName();
 7         try {
 8             UtilTimerStack.push(timerKey);
 9
10             Object methodResult;
11             try {
12                 methodResult = ognlUtil.callMethod(methodName + "()", getStack().getContext(), action);//执行action类实例
13             } catch (MethodFailedException e) {
14                 // if reason is missing method,  try checking UnknownHandlers
15                 if (e.getReason() instanceof NoSuchMethodException) {
16                     if (unknownHandlerManager.hasUnknownHandlers()) {
17                         try {
18                             methodResult = unknownHandlerManager.handleUnknownMethod(action, methodName);
19                         } catch (NoSuchMethodException ignore) {
20                             // throw the original one
21                             throw e;
22                         }
23                     } else {
24                         // throw the original one
25                         throw e;
26                     }
27                     // throw the original exception as UnknownHandlers weren't able to handle invocation as well
28                     if (methodResult == null) {
29                         throw e;
30                     }
31                 } else {
32                     // exception isn't related to missing action method, throw it
33                     throw e;
34                 }
35             }
36             return saveResult(actionConfig, methodResult);
37         } catch (NoSuchPropertyException e) {
38             throw new IllegalArgumentException("The " + methodName + "() is not defined in action " + getAction().getClass() + "");
39         } catch (MethodFailedException e) {
40             // We try to return the source exception.
41             Throwable t = e.getCause();
42
43             if (actionEventListener != null) {
44                 String result = actionEventListener.handleException(t, getStack());
45                 if (result != null) {
46                     return result;
47                 }
48             }
49             if (t instanceof Exception) {
50                 throw (Exception) t;
51             } else {
52                 throw e;
53             }
54         } finally {
55             UtilTimerStack.pop(timerKey);
56         }
57     }

这个方法的做的事情是很简单。就是获得当前action类实例要执行的方法名。在根据OgnlUtil工具类在执行对应action类实例的方法。显然想要知道更深一点的话就必须深入OgnlUtil工具类的源码。让我们看一下吧。
OgnlUtil类:

1 public Object callMethod(final String name, final Map<String, Object> context, final Object root) throws OgnlException {
2         return compileAndExecuteMethod(name, context, new OgnlTask<Object>() {
3             public Object execute(Object tree) throws OgnlException {
4                 return Ognl.getValue(tree, context, root);
5             }
6         });
7     }

OgnlUtil类:

private <T> Object compileAndExecuteMethod(String expression, Map<String, Object> context, OgnlTask<T> task) throws OgnlException {
        Object tree;
        if (enableExpressionCache) {
            tree = expressions.get(expression);
            if (tree == null) {
                tree = Ognl.parseExpression(expression);
                checkSimpleMethod(tree, context);
            }
        } else {
            tree = Ognl.parseExpression(expression);
            checkSimpleMethod(tree, context);
        }
        final T exec = task.execute(tree);
        // if cache is enabled and it's a valid expression, puts it in
        if(enableExpressionCache) {
            expressions.putIfAbsent(expression, tree);
        }
        return exec;
    }

笔者看到这里的时候就有一点心烦。主要是一看就知道又要去学习一下关于ONGL相关的语法。这一点请读者自己去补充。Ognl.getValue(tree, context, root)这句代码就是ONGL语法的体现。其中tree就是ONGL的表达式。root就是根对象。即是用户action类实例。对于context笔者还真不知道要什么去讲解他。笔者把他理解为ONGL的上下文。通常跟ONGL表达式里面的“#”号相关。简单讲就是Ognl.getValue(tree, context, root)就是执行action方法。而接下深入就是ognl.jar的源码了。已经跳出了struts2源码的范围了。
执行完上面的代码之后,就开始保存相应的结果。saveResult方法就是用于处理结果的。如果结果值是Result类型的话,就把他存在成员变量explicitResult上,并返回NULL。否则就转为String类型并返回。代码如下

 1 protected String saveResult(ActionConfig actionConfig, Object methodResult) {
 2         if (methodResult instanceof Result) {
 3             this.explicitResult = (Result) methodResult;
 4
 5             // Wire the result automatically
 6             container.inject(explicitResult);
 7             return null;
 8         } else {
 9             return (String) methodResult;
10         }
11     }

如果笔者没有查看源码的话,就不会知道原来action类实例在执行结束之后不只是一个String类型。还有一个叫Result类。如果有硬的讲的话,笔者觉得只是返回一个Result类。让我们看下面一段代码。就知道笔者为什么会有这样子的感觉。
1 // now execute the result, if we're supposed to
2 if (proxy.getExecuteResult()) {
3 executeResult();
4 }
上面这段代码是在DefaultActionInvocation类的invoke方法的后半部分。如果返回的结果是字符串,最后还是会根据字符串来获得对应的Result类的实例。Result类的实例类却很多。如ServletDispatcherResult类等。找到了Result类的实例就会去执行他本身的execute方法。我们可以在executeResult方法的源码里面体现出来。看一下吧。
DefaultActionInvocation类:

 1 private void executeResult() throws Exception {
 2         result = createResult();
 3
 4         String timerKey = "executeResult: " + getResultCode();
 5         try {
 6             UtilTimerStack.push(timerKey);
 7             if (result != null) {
 8                 result.execute(this);
 9             } else if (resultCode != null && !Action.NONE.equals(resultCode)) {
10                 throw new ConfigurationException("No result defined for action " + getAction().getClass().getName()
11                         + " and result " + getResultCode(), proxy.getConfig());
12             } else {
13                 if (LOG.isDebugEnabled()) {
14                     LOG.debug("No result returned for action {} at {}", getAction().getClass().getName(), proxy.getConfig().getLocation());
15                 }
16             }
17         } finally {
18             UtilTimerStack.pop(timerKey);
19         }
20     }

DefaultActionInvocation类:

 1 public Result createResult() throws Exception {
 2         LOG.trace("Creating result related to resultCode [{}]", resultCode);
 3
 4         if (explicitResult != null) {
 5             Result ret = explicitResult;
 6             explicitResult = null;
 7
 8             return ret;
 9         }
10         ActionConfig config = proxy.getConfig();
11         Map<String, ResultConfig> results = config.getResults();
12
13         ResultConfig resultConfig = null;
14
15         try {
16             resultConfig = results.get(resultCode);
17         } catch (NullPointerException e) {
18             LOG.debug("Got NPE trying to read result configuration for resultCode [{}]", resultCode);
19         }
20
21         if (resultConfig == null) {
22             // If no result is found for the given resultCode, try to get a wildcard '*' match.
23             resultConfig = results.get("*");
24         }
25
26         if (resultConfig != null) {
27             try {
28                 return objectFactory.buildResult(resultConfig, invocationContext.getContextMap());
29             } catch (Exception e) {
30                 LOG.error("There was an exception while instantiating the result of type {}", resultConfig.getClassName(), e);
31                 throw new XWorkException(e, resultConfig);
32             }
33         } else if (resultCode != null && !Action.NONE.equals(resultCode) && unknownHandlerManager.hasUnknownHandlers()) {
34             return unknownHandlerManager.handleUnknownResult(invocationContext, proxy.getActionName(), proxy.getConfig(), resultCode);
35         }
36         return null;
37     }

前一段代码:讲述executeResult方法。executeResult方法只是用于执行Result类的实例。即是执行Result类的execute方法。
后一段代码:进述executeResult方法里面用到的createResult方法。也就是笔者前面讲到的会根据返回的结果字符串来获得对应的Result类的实例。我们可以看到如果他返回是一个Result类的话,就直接返回。如果不是,就是从配置信息里面获得对应在的result元素节点信息。通过result元素节点信息来生成对应的Result类的实例。显然我们可以看到ObjectFactory类又在一次发挥了作用。在前面action类实例也是靠他来完成的。
到这里,相信有部分读者会跟笔者一样子有一个疑问?Result类到底是什么东东。其实他是用于对action类实例执行之后结果的处理。简单点讲可以理解为处理网页。结果也有了。接下来便是返回结果给用户显示出来。我们也看到了在这个过程中DefaultActionInvocation类实现做了很多的工作。包括拦截器的调用。返回Result类的处理。不得说DefaultActionInvocation类真的很重要。
| 本章总结 | 
本章主要是进述DefaultActionInvocation类执行action的相关内容。让我们知道了是如何进行的执行action。其中用到ONGL相关的语法。也知道了action类实例执行之后。还会有对应的结果处理。当然这些用是交给于Result类的实例。
DefaultActionInvocation类的执行action的更多相关文章
- Struts2 源码分析——DefaultActionInvocation类的执行action
		本章简言 上一章讲到关于拦截器的机制的知识点,让我们对拦截器有了一定的认识.我们也清楚的知道在执行用户action类实例之前,struts2会先去执行当前action类对应的拦截器.而关于在哪里执行a ... 
- Struts2 源码分析——调结者(Dispatcher)之执行action
		章节简言 上一章笔者写关于Dispatcher类如何处理接受来的request请求.当然读者们也知道他并非正真的执行action操作.他只是在执行action操作之前的准备工作.那么谁才是正真的执行a ... 
- 调结者(Dispatcher)之执行action
		调结者的执行action StrutsExecuteFilter类的工作就是执行对应的action请求.StrutsExecuteFilter类的工作还需要有一个叫ExecuteOperations类 ... 
- 在执行Action之间检验是否登录
		在执行Action之间检验是否登录,也可以在执行Action前先执行某一个操作 public class BaseController : Controller { protected string ... 
- Java类的执行顺序
		在Java中一个类包括:构造块.构造方法.静态块.main方法.普通方法. 通过下面的例子将看出一个类中各种方法的执行顺序: /** * @author zhengbinMac */ public c ... 
- 用ArcMap在PostgreSQL中创建要素类需要执行”create enterprise geodatabase”吗
		问:用Acmap在PostgreSQL中创建要素类需要执行"create enterprise geodatabase"吗? 关于这个问题,是在为新员工做postgresql培训后 ... 
- Java类初始化执行流程
		测试代码: package com.test.ClassLaoderTest; public class test1 { public static String s_variable = " ... 
- How to: 执行Action当收到数据时
		本文旨在演示ActionBlock的使用. 大致流程: 输入路径--读取字节--计算--传输到打印 // Demonstrates how to provide delegates to ex ... 
- [1]朝花夕拾-JAVA类的执行顺序
		最近在温习java的基础,刷题刷到java的执行顺序,很汗颜,答案回答错了! 题目类似如下: package com.phpdragon.study.base; public class ExecOr ... 
随机推荐
- MQTT---HiveMQ源代码具体解释(七)Netty-SSL/NoSSL
			源博客地址:http://blog.csdn.net/pipinet123 MQTT交流群:221405150 实现功能 依据用户配置的不同的Listener(TcpListener.TlsTcpLi ... 
- 【服务器时间修改为东八区】包括Apache2和mysql
			1.服务器Apache时间修改,可通过修改php.ini进行修改 所以就深入了解了一下, 发现Apache(PHP)的服务器时间时区默认为UTC(Coordinated UniversalTime 世 ... 
- Idea golang "can’t find import" 解决方法
			如题,在使用leveldb go wrapper levigo 的时候,本地安装好levigo后,通过命令行编译代码正常并能work,但在Idea中使用时出现: can't find import & ... 
- Oracle学习-Power Designer、visio 2003、Oracle sql developer、OEM、expdp
			Oracle的体系太庞大了.对于刚開始学习的人来说,难免有些无从下手的感觉. 经过一学期的学习对Oracle学习有了一些深入的了解,由于之前学习过Oracle的一些主要的知识.所以学习起来上手比較快一 ... 
- VS2015 经常不出现智能提示,代码颜色也没有了
			重置下.开始菜单 -->所有程序-->Visual Studio 文件夹 --> Visual Studio Tools --> Developer Command Promp ... 
- MyEclipse中背景颜色的设定
			设置代码编写区域背景色的方法: Window-->Preferences-->General-->Editors-->TextEditors-->在Appearance ... 
- Form.ShowWithoutActivation 属性
			获取一个值,该值指示显示窗口时是否激活它. 命名空间: System.Windows.Forms程序集: System.Windows.Forms(在 System.Windows.Forms.d ... 
- “互联网+”取代O2O将成为2016最大风口
			2016年的最大风口是“互联网+”,经历了O2O的洗礼,B2C服务的全线崛起.跨界与场景打造的极致体验,从0到1的产业开放,都将在这一年集体爆发,“互联网+”比O2O更加接地气,更具有完整的商业模式和 ... 
- maven依赖workspace和jar包
			当开发maven项目时,如果workspace中有maven依赖的项目,并且groupid和artifactId都相同,maven就会优先依赖workspace中的项目文件,如果想依赖maven库中的 ... 
- 语言中.C文件和.H文件的概念和联系
			//a.h void foo(); //a.c #include "a.h" //我的问题出来了:这句话是要,还是不要? void foo() { return; } //main ... 
