Struts2.0中ActionInvocation使用 (轉)


[-]

  1.  方法一:使用現成的PreResultListener監聽器事件
  2. 方法二,實現自己的 ActionInvocation ,手動分離Action和Result的執行
 
 Interceptor說明

Interceptor的接口定義沒有什么特別的地方,除了init和destory方法以外,intercept方法是實現整個攔截器機制的核心方法。而它所依賴的參數ActionInvocation則是我們之前章節中曾經提到過的著名的Action調度者

我在這里需要指出的是一個很重要的方法invocation.invoke()。這是ActionInvocation中的方法,而ActionInvocation是Action調度者,所以這個方法具備以下2層含義(詳細看DefaultActionInvocation源代碼):
1. 如果攔截器堆棧中還有其他的Interceptor,那么invocation.invoke()將調用堆棧中下一個Interceptor的執行。

2. 如果攔截器堆棧中只有Action了,那么invocation.invoke()將調用Action執行。

 

3.

DefaultActionInvocation部分源代碼:

      if (interceptors.hasNext()) {
       final InterceptorMapping interceptor = (InterceptorMapping) interceptors.next();
       UtilTimerStack.profile("interceptor: "+interceptor.getName(),
         new UtilTimerStack.ProfilingBlock<String>() {
       public String doProfiling() throws Exception {
           resultCode = interceptor.getInterceptor().intercept(DefaultActionInvocation.this);//遞歸調用攔截器
           return null;
       }
       });
      } else {
       resultCode = invokeActionOnly();
      }

每個攔截器中的代碼的執行順序,在Action之前,攔截器的執行順序與堆棧中定義的一致;而在Action和Result之后,攔截器的執行順序與堆棧中定義的順序相反。

Interceptor攔截類型

從上面的分析,我們知道,整個攔截器的核心部分是invocation.invoke()這個函數的調用位置。事實上,我們也正式根據這句代碼的調用位置,來進行攔截類型的區分的。在Struts2中,Interceptor的攔截類型,分成以下三類:

1. before

before攔截,是指在攔截器中定義的代碼,它們存在於invocation.invoke()代碼執行之前。這些代碼,將依照攔截器定義的順序,順序執行

2. after

after攔截,是指在攔截器中定義的代碼,它們存在於invocation.invoke()代碼執行之后。這些代碼,將一招攔截器定義的順序,逆序執行

 

PreResultListener
有的時候,before攔截和after攔截對我們來說是不夠的,因為我們需要在Action執行完之后,但是還沒有回到視圖層之前,做一些事情。Struts2同樣支持這樣的攔截,這種攔截方式,是通過在攔截器中注冊一個PreResultListener的接口來實現的。

如:在攔截器中使用如下代碼,其中MyPreResultListener實現了PreResultListener 接口並在beforeResult方法中做了一些事情然后在攔截器類中加入action.addPreResultListener(new MyPreResultListener());

 

從源碼中,我們可以看到,我們之前提到的Struts2的Action層的4個不同的層次,在這個方法中都有體現,他們分別是:攔截器(Interceptor)、Action、PreResultListener和Result。在這個方法中,保證了這些層次的有序調用和執行

 

問題

使用Struts2作為web框架,知道它的攔截器(Interceptor)機制,類似與Filter和Spring的AOP,於是實現了一個為Action增加自定義前置(before)動作和后置動作(after)的攔截器(曰:WInterceptor),不過用一段時間發現,在WInterceptor的after中,對Action對象的屬性修改在頁面看不到,對請求對象的屬性設置也無效。為什么在調用了Action之后(invokeAction())之后,request就不能使用了呢,攔截器不能改變Action的Result么?

 問題的關鍵在於,在調用actionInvocation.invoke()的之后,不僅執行類Action,也執行類Result。因而,等退回到攔截器的調用代碼時,Result已經生成,View已經確定,這時你再修改模型(Action的屬性)或請求對象的屬性,對視圖不會有任何影響。

解決辦法:

 

 方法一:使用現成的PreResultListener監聽器事件

 

 

搞清楚原因,卷起袖子干吧,只要讓WInterpretor的after事件,放在Result的生成之前就行了。

看看XWork的攔截器接口注入的actionInvocation,其實就提供增加Result執行的前置監聽事件-PreResultListener:

/**  
  1.  * Register a {@link PreResultListener} to be notified after the Action is executed and  
  2.  * before the Result is executed.  
  3.  * <p/>  
  4.  * The ActionInvocation implementation must guarantee that listeners will be called in  
  5.  * the order in which they are registered.  
  6.  * <p/>  
  7.  * Listener registration and execution does not need to be thread-safe.  
  8.  *  
  9.  * @param listener the listener to add.  
  10.  */  
  11. void addPreResultListener(PreResultListener listener);  
/** * Register a {@link PreResultListener} to be notified after the Action is executed and * before the Result is executed. * <p/> * The ActionInvocation implementation must guarantee that listeners will be called in * the order in which they are registered. * <p/> * Listener registration and execution does not need to be thread-safe. * * @param listener the listener to add. */ void addPreResultListener(PreResultListener listener);
 
          

 

因此,讓攔截器實現這個接口,就可以自然實現Action執行after事件了。

 

 

方法二,實現自己的 ActionInvocation ,手動分離Action和Result的執行

本來前面的方法已經很好了,可是,可是啊,在addPreResultListener里的異常,不會被Struts的框架捕獲,而且,addPreResultListener接口不能傳遞自己的上下文參數,難道動用ThreadLocal傳參?

 

研究了一下XWork的ActionInvocation 接口默認實現類DefaultActionInvocation, 寫了一個包裝類,將Action的執行和Result的生成完全分開,或許有人用的着,放上來,見附件(ActionInvocationWrapper),如有不妥之處請告知。

 

exeucteAction是執行Action,executeResult是執行Result


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM