溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

DefaultActionInvocation類的執(zhí)行action

發(fā)布時(shí)間:2020-08-03 20:20:43 來源:網(wǎng)絡(luò) 閱讀:394 作者:張濤澤 欄目:網(wǎng)絡(luò)安全
本章簡(jiǎn)言

上一章講到關(guān)于攔截器的機(jī)制的知識(shí)點(diǎn),讓我們對(duì)攔截器有了一定的認(rèn)識(shí)。我們也清楚的知道在執(zhí)行用戶action類實(shí)例之前,struts2會(huì)先去執(zhí)行當(dāng)前action類對(duì)應(yīng)的攔截器。而關(guān)于在哪里執(zhí)行action類實(shí)例,筆者根本就沒有詳細(xì)的講到。更多只是幾筆帶過而以。雖然在《Struts2 源碼分析——Action代理類的工作》章節(jié)里面也講到過關(guān)于DefaultActionInvocation類的一些作用。提過DefaultActionInvocation類會(huì)去執(zhí)行action類實(shí)例。但是還是沒有具體的指出重點(diǎn)的代碼。而本章就是來講執(zhí)行action類實(shí)例的代碼落在哪里。即是DefaultActionInvocation類的invokeAction方法。

 DefaultActionInvocation類的執(zhí)行action

上一章里面有提到過DefaultActionInvocation類的invoke方法里面的invokeActionOnly方法。沒有錯(cuò)!當(dāng)所有攔截器前半部分執(zhí)行結(jié)束之后,就會(huì)去執(zhí)行invokeActionOnly方法。這個(gè)方法就是執(zhí)行action類實(shí)例的入口。而invokeActionOnly方法實(shí)際是去調(diào)用本身類的invokeAction方法??匆幌麓a就知道了。

DefaultActionInvocation類:

1 public String invokeActionOnly() throws Exception {2         return invokeAction(getAction(), proxy.getConfig());3     }

代碼里面getAction方法就是獲得action類實(shí)例。即是跟《Struts2 源碼分析——Action代理類的工作》章節(jié)里面講到的createAction方法有關(guān)。當(dāng)程序執(zhí)行到這里的時(shí)候,createAction方法已經(jīng)新建好了action類實(shí)例。不清楚讀者請(qǐng)到這章去看一下。讓我們看一下invokeAction方法的源碼吧。

DefaultActionInvocation類的執(zhí)行action

 1 protected String invokeAction(Object action, ActionConfig actionConfig) throws Exception { 2         String methodName = proxy.getMethod();//獲得要執(zhí)行的方法名。 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);//執(zhí)行action類實(shí)例13             } catch (MethodFailedException e) {14                 // if reason is missing method,  try checking UnknownHandlers15                 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 one21                             throw e;22                         }23                     } else {24                         // throw the original one25                         throw e;26                     }27                     // throw the original exception as UnknownHandlers weren't able to handle invocation as well28                     if (methodResult == null) {29                         throw e;30                     }31                 } else {32                     // exception isn't related to missing action method, throw it33                     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     }

DefaultActionInvocation類的執(zhí)行action

這個(gè)方法的做的事情是很簡(jiǎn)單。就是獲得當(dāng)前action類實(shí)例要執(zhí)行的方法名。在根據(jù)OgnlUtil工具類在執(zhí)行對(duì)應(yīng)action類實(shí)例的方法。顯然想要知道更深一點(diǎn)的話就必須深入OgnlUtil工具類的源碼。讓我們看一下吧。

OgnlUtil類:

DefaultActionInvocation類的執(zhí)行action

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     }

DefaultActionInvocation類的執(zhí)行action

OgnlUtil類:

DefaultActionInvocation類的執(zhí)行action

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;
    }

DefaultActionInvocation類的執(zhí)行action

筆者看到這里的時(shí)候就有一點(diǎn)心煩。主要是一看就知道又要去學(xué)習(xí)一下關(guān)于ONGL相關(guān)的語法。這一點(diǎn)請(qǐng)讀者自己去補(bǔ)充。Ognl.getValue(tree, context, root)這句代碼就是ONGL語法的體現(xiàn)。其中tree就是ONGL的表達(dá)式。root就是根對(duì)象。即是用戶action類實(shí)例。對(duì)于context筆者還真不知道要什么去講解他。筆者把他理解為ONGL的上下文。通常跟ONGL表達(dá)式里面的“#”號(hào)相關(guān)。簡(jiǎn)單講就是Ognl.getValue(tree, context, root)就是執(zhí)行action方法。而接下深入就是ognl.jar的源碼了。已經(jīng)跳出了struts2源碼的范圍了。

執(zhí)行完上面的代碼之后,就開始保存相應(yīng)的結(jié)果。saveResult方法就是用于處理結(jié)果的。如果結(jié)果值是Result類型的話,就把他存在成員變量explicitResult上,并返回NULL。否則就轉(zhuǎn)為String類型并返回。代碼如下

DefaultActionInvocation類的執(zhí)行action

 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     }

DefaultActionInvocation類的執(zhí)行action

如果筆者沒有查看源碼的話,就不會(huì)知道原來action類實(shí)例在執(zhí)行結(jié)束之后不只是一個(gè)String類型。還有一個(gè)叫Result類。如果有硬的講的話,新航道托福筆者覺得只是返回一個(gè)Result類。讓我們看下面一段代碼。就知道筆者為什么會(huì)有這樣子的感覺。

1            // now execute the result, if we're supposed to2                 if (proxy.getExecuteResult()) {3                     executeResult();4                 }

上面這段代碼是在DefaultActionInvocation類的invoke方法的后半部分。如果返回的結(jié)果是字符串,最后還是會(huì)根據(jù)字符串來獲得對(duì)應(yīng)的Result類的實(shí)例。Result類的實(shí)例類卻很多。如ServletDispatcherResult類等。找到了Result類的實(shí)例就會(huì)去執(zhí)行他本身的execute方法。我們可以在executeResult方法的源碼里面體現(xiàn)出來??匆幌掳?。

DefaultActionInvocation類:

DefaultActionInvocation類的執(zhí)行action

 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類的執(zhí)行action

DefaultActionInvocation類:

DefaultActionInvocation類的執(zhí)行action

 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     }

DefaultActionInvocation類的執(zhí)行action

前一段代碼:講述executeResult方法。executeResult方法只是用于執(zhí)行Result類的實(shí)例。即是執(zhí)行Result類的execute方法。

后一段代碼:進(jìn)述executeResult方法里面用到的createResult方法。也就是筆者前面講到的會(huì)根據(jù)返回的結(jié)果字符串來獲得對(duì)應(yīng)的Result類的實(shí)例。我們可以看到如果他返回是一個(gè)Result類的話,就直接返回。如果不是,就是從配置信息里面獲得對(duì)應(yīng)在的result元素節(jié)點(diǎn)信息。通過result元素節(jié)點(diǎn)信息來生成對(duì)應(yīng)的Result類的實(shí)例。顯然我們可以看到ObjectFactory類又在一次發(fā)揮了作用。在前面action類實(shí)例也是靠他來完成的。

到這里,相信有部分讀者會(huì)跟筆者一樣子有一個(gè)疑問?Result類到底是什么東東。其實(shí)他是用于對(duì)action類實(shí)例執(zhí)行之后結(jié)果的處理。簡(jiǎn)單點(diǎn)講可以理解為處理網(wǎng)頁。結(jié)果也有了。接下來便是返回結(jié)果給用戶顯示出來。我們也看到了在這個(gè)過程中DefaultActionInvocation類實(shí)現(xiàn)做了很多的工作。包括攔截器的調(diào)用。返回Result類的處理。不得說DefaultActionInvocation類真的很重要。

本章總結(jié)

本章主要是進(jìn)述DefaultActionInvocation類執(zhí)行action的相關(guān)內(nèi)容。讓我們知道了是如何進(jìn)行的執(zhí)行action。其中用到ONGL相關(guān)的語法。也知道了action類實(shí)例執(zhí)行之后。還會(huì)有對(duì)應(yīng)的結(jié)果處理。當(dāng)然這些用是交給于Result類的實(shí)例。


向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI