Struts2源碼閱讀(六)_ActionProxy&ActionInvocation

來源:互聯網
上載者:User

下面開始講一下主菜ActionProxy了.在這之前最好先去瞭解一下動態Proxy的基本知識.
ActionProxy是Action的一個代理類,也就是說Action的調用是通過ActionProxy實現的,其實就是調用了ActionProxy.execute()方法,而該方法又調用了ActionInvocation.invoke()方法。歸根到底,最後調用的是DefaultActionInvocation.invokeAction()方法。
DefaultActionInvocation()->init()->createAction()。
最後通過調用ActionProxy.exute()-->ActionInvocation.invoke()-->Intercepter.intercept()-->ActionInvocation.invokeActionOnly()-->invokeAction()
這裡的步驟是先由ActionProxyFactory建立ActionInvocation和ActionProxy.

public ActionProxy createActionProxy(String namespace, String actionName, String methodName, Map<String, Object> extraContext, boolean executeResult, boolean cleanupContext) { </p><p> ActionInvocation inv = new DefaultActionInvocation(extraContext, true);<br /> container.inject(inv);<br /> return createActionProxy(inv, namespace, actionName, methodName, executeResult, cleanupContext);<br />}

 下面先看DefaultActionInvocation的init方法

public void init(ActionProxy proxy) {<br /> this.proxy = proxy;<br /> Map<String, Object> contextMap = createContextMap(); </p><p> // Setting this so that other classes, like object factories, can use the ActionProxy and other<br /> // contextual information to operate<br /> ActionContext actionContext = ActionContext.getContext(); </p><p> if (actionContext != null) {<br /> actionContext.setActionInvocation(this);<br /> }<br /> //建立Action,struts2中每一個Request都會建立一個新的Action<br /> createAction(contextMap); </p><p> if (pushAction) {<br /> stack.push(action);<br /> contextMap.put("action", action);<br /> } </p><p> invocationContext = new ActionContext(contextMap);<br /> invocationContext.setName(proxy.getActionName()); </p><p> // get a new List so we don't get problems with the iterator if someone changes the list<br /> List<InterceptorMapping> interceptorList = new ArrayList<InterceptorMapping>(proxy.getConfig().getInterceptors());<br /> interceptors = interceptorList.iterator();<br />} </p><p>protected void createAction(Map<String, Object> contextMap) {<br /> // load action<br /> String timerKey = "actionCreate: " + proxy.getActionName();<br /> try {<br /> UtilTimerStack.push(timerKey);<br /> //預設為SpringObjectFactory:struts.objectFactory=spring.這裡非常巧妙,在struts.properties中可以重寫這個屬性<br /> //在前面BeanSelectionProvider中通過設定檔為ObjectFactory設定實作類別<br /> //這裡以Spring為例,這裡會調到SpringObjectFactory的buildBean方法,可以通過ApplicationContext的getBean()方法得到Spring的Bean<br /> action = objectFactory.buildAction(proxy.getActionName(), proxy.getNamespace(), proxy.getConfig(), contextMap);<br /> } catch (InstantiationException e) {<br /> throw new XWorkException("Unable to intantiate Action!", e, proxy.getConfig());<br /> } catch (IllegalAccessException e) {<br /> throw new XWorkException("Illegal access to constructor, is it public?", e, proxy.getConfig());<br /> } catch (Exception e) {<br /> ...<br /> } finally {<br /> UtilTimerStack.pop(timerKey);<br /> } </p><p> if (actionEventListener != null) {<br /> action = actionEventListener.prepare(action, stack);<br /> }<br />}<br />//SpringObjectFactory<br />public Object buildBean(String beanName, Map<String, Object> extraContext, boolean injectInternal) throws Exception {<br /> Object o = null;<br /> try {<br /> //SpringObjectFactory會通過web.xml中的context-param:contextConfigLocation自動注入ClassPathXmlApplicationContext<br /> o = appContext.getBean(beanName);<br /> } catch (NoSuchBeanDefinitionException e) {<br /> Class beanClazz = getClassInstance(beanName);<br /> o = buildBean(beanClazz, extraContext);<br /> }<br /> if (injectInternal) {<br /> injectInternalBeans(o);<br /> }<br /> return o;<br />}<br />

//接下來看看DefaultActionInvocation 的invoke方法<br />public String invoke() throws Exception {<br /> String profileKey = "invoke: ";<br /> try {<br /> UtilTimerStack.push(profileKey); </p><p> if (executed) {<br /> throw new IllegalStateException("Action has already executed");<br /> }<br /> //遞迴執行interceptor<br /> if (interceptors.hasNext()) {<br /> //interceptors是InterceptorMapping實際上是像一個像FilterChain一樣的Interceptor鏈<br /> //通過調用Invocation.invoke()實現遞迴牡迴圈<br /> final InterceptorMapping interceptor = (InterceptorMapping) interceptors.next();<br /> String interceptorMsg = "interceptor: " + interceptor.getName();<br /> UtilTimerStack.push(interceptorMsg);<br /> try {<br /> //在每個Interceptor的方法中都會return invocation.invoke()<br /> resultCode = interceptor.getInterceptor().intercept(DefaultActionInvocation.this);<br /> }<br /> finally {<br /> UtilTimerStack.pop(interceptorMsg);<br /> }<br /> } else {<br /> //當所有interceptor都執行完,最後執行Action,invokeActionOnly會調用invokeAction()方法<br /> resultCode = invokeActionOnly();<br /> } </p><p> // this is needed because the result will be executed, then control will return to the Interceptor, which will<br /> // return above and flow through again<br /> //在Result返回之前調用preResultListeners<br /> //通過executed控制,只執行一次<br /> if (!executed) {<br /> if (preResultListeners != null) {<br /> for (Object preResultListener : preResultListeners) {<br /> PreResultListener listener = (PreResultListener) preResultListener; </p><p> String _profileKey = "preResultListener: ";<br /> try {<br /> UtilTimerStack.push(_profileKey);<br /> listener.beforeResult(this, resultCode);<br /> }<br /> finally {<br /> UtilTimerStack.pop(_profileKey);<br /> }<br /> }<br /> } </p><p> // now execute the result, if we're supposed to<br /> //執行Result<br /> if (proxy.getExecuteResult()) {<br /> executeResult();<br /> } </p><p> executed = true;<br /> } </p><p> return resultCode;<br /> }<br /> finally {<br /> UtilTimerStack.pop(profileKey);<br /> }<br />} </p><p>//invokeAction<br />protected String invokeAction(Object action,ActionConfig actionConfig)throws Exception{<br /> String methodName = proxy.getMethod(); </p><p> String timerKey = "invokeAction: " + proxy.getActionName();<br /> try {<br /> UtilTimerStack.push(timerKey); </p><p> boolean methodCalled = false;<br /> Object methodResult = null;<br /> Method method = null;<br /> try {<br /> //java反射機製得到要執行的方法<br /> method = getAction().getClass().getMethod(methodName, new Class[0]);<br /> } catch (NoSuchMethodException e) {<br /> // hmm -- OK, try doXxx instead<br /> //如果沒有對應的方法,則使用do+Xxxx來再次獲得方法<br /> try {<br /> String altMethodName = "do" + methodName.substring(0, 1).toUpperCase() + methodName.substring(1);<br /> method = getAction().getClass().getMethod(altMethodName, new Class[0]);<br /> } catch (NoSuchMethodException e1) {<br /> // well, give the unknown handler a shot<br /> if (unknownHandlerManager.hasUnknownHandlers()) {<br /> try {<br /> methodResult = unknownHandlerManager.handleUnknownMethod(action, methodName);<br /> methodCalled = true;<br /> } catch (NoSuchMethodException e2) {<br /> // throw the original one<br /> throw e;<br /> }<br /> } else {<br /> throw e;<br /> }<br /> }<br /> }<br /> //執行Method<br /> if (!methodCalled) {<br /> methodResult = method.invoke(action, new Object[0]);<br /> }<br /> //從這裡可以看出可以Action的方法可以返回String去匹配Result,也可以直接返回Result類<br /> if (methodResult instanceof Result) {<br /> this.explicitResult = (Result) methodResult; </p><p> // Wire the result automatically<br /> container.inject(explicitResult);<br /> return null;<br /> } else {<br /> return (String) methodResult;<br /> }<br /> } catch (NoSuchMethodException e) {<br /> throw new IllegalArgumentException("The " + methodName + "() is not defined in action " + getAction().getClass() + "");<br /> } catch (InvocationTargetException e) {<br /> // We try to return the source exception.<br /> Throwable t = e.getTargetException(); </p><p> if (actionEventListener != null) {<br /> String result = actionEventListener.handleException(t, getStack());<br /> if (result != null) {<br /> return result;<br /> }<br /> }<br /> if (t instanceof Exception) {<br /> throw (Exception) t;<br /> } else {<br /> throw e;<br /> }<br /> } finally {<br /> UtilTimerStack.pop(timerKey);<br /> }<br />}

action執行完了,還要根據ResultConfig返回到view,也就是在invoke方法中調用executeResult方法。

private void executeResult() throws Exception {<br /> //根據ResultConfig建立Result<br /> result = createResult(); </p><p> String timerKey = "executeResult: " + getResultCode();<br /> try {<br /> UtilTimerStack.push(timerKey);<br /> if (result != null) {<br /> //開始執行Result,<br /> //可以參考Result的實現,如用了比較多的ServletDispatcherResult,ServletActionRedirectResult,ServletRedirectResult<br /> result.execute(this);<br /> } else if (resultCode != null && !Action.NONE.equals(resultCode)) {<br /> throw new ConfigurationException("No result defined for action " + getAction().getClass().getName()<br /> + " and result " + getResultCode(), proxy.getConfig());<br /> } else {<br /> if (LOG.isDebugEnabled()) {<br /> LOG.debug("No result returned for action " + getAction().getClass().getName() + " at " + proxy.getConfig().getLocation());<br /> }<br /> }<br /> } finally {<br /> UtilTimerStack.pop(timerKey);<br /> }<br />} </p><p>public Result createResult() throws Exception {<br /> //如果Action中直接返回的Result類型,在invokeAction()儲存在explicitResult<br /> if (explicitResult != null) {<br /> Result ret = explicitResult;<br /> explicitResult = null; </p><p> return ret;<br /> }<br /> //返回的是String則從config中得到當前Action的Results列表<br /> ActionConfig config = proxy.getConfig();<br /> Map<String, ResultConfig> results = config.getResults(); </p><p> ResultConfig resultConfig = null; </p><p> synchronized (config) {<br /> try {<br /> //通過返回的String來匹配resultConfig<br /> resultConfig = results.get(resultCode);<br /> } catch (NullPointerException e) {<br /> // swallow<br /> }<br /> if (resultConfig == null) {<br /> // If no result is found for the given resultCode, try to get a wildcard '*' match.<br /> //如果找不到對應name的ResultConfig,則使用name為*的Result<br /> //說明可以用*通配所有的Result<br /> resultConfig = results.get("*");<br /> }<br /> } </p><p> if (resultConfig != null) {<br /> try {<br /> //建立Result<br /> return objectFactory.buildResult(resultConfig, invocationContext.getContextMap());<br /> } catch (Exception e) {<br /> LOG.error("There was an exception while instantiating the result of type " + resultConfig.getClassName(), e);<br /> throw new XWorkException(e, resultConfig);<br /> }<br /> } else if (resultCode != null && !Action.NONE.equals(resultCode) && unknownHandlerManager.hasUnknownHandlers()) {<br /> return unknownHandlerManager.handleUnknownResult(invocationContext, proxy.getActionName(), proxy.getConfig(), resultCode);<br /> }<br /> return null;<br />} </p><p>public Result buildResult(ResultConfig resultConfig, Map<String, Object> extraContext) throws Exception {<br /> String resultClassName = resultConfig.getClassName();<br /> Result result = null; </p><p> if (resultClassName != null) {<br /> //buildBean中會用反射機制Class.newInstance來建立bean<br /> result = (Result) buildBean(resultClassName, extraContext);<br /> Map<String, String> params = resultConfig.getParams();<br /> if (params != null) {<br /> for (Map.Entry<String, String> paramEntry : params.entrySet()) {<br /> try {<br /> //reflectionProvider參見OgnlReflectionProvider;<br /> //resultConfig.getParams()就是result設定檔裡所配置的參數<param></param><br /> //setProperties方法最終調用的是Ognl類的setValue方法<br /> //這句其實就是把param名值設定到根對象result上<br /> reflectionProvider.setProperty(paramEntry.getKey(), paramEntry.getValue(), result, extraContext, true);<br /> } catch (ReflectionException ex) {<br /> if (LOG.isErrorEnabled())<br /> LOG.error("Unable to set parameter [#0] in result of type [#1]", ex,<br /> paramEntry.getKey(), resultConfig.getClassName());<br /> if (result instanceof ReflectionExceptionHandler) {<br /> ((ReflectionExceptionHandler) result).handle(ex);<br /> }<br /> }<br /> }<br /> }<br /> } </p><p> return result;<br />}

最後看一張在網上看到的一個調用流程圖作為參考:

Come From:http://qidaoxp.javaeye.com/blog/503015

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.