struts2 攔截器和actioninvocation

1、Interceptor說明

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

  在這裏須要指出的是一個很重要的方法invocation.invoke()。這是ActionInvocation中的方法,而ActionInvocation是Action調度者,因此這個方法具有如下2層含義(詳細看DefaultActionInvocation源代碼): 
  一、 若是攔截器堆棧中還有其餘的Interceptor,那麼invocation.invoke()將調用堆棧中下一個Interceptor的執行。 
  二、 若是攔截器堆棧中只有Action了,那麼invocation.invoke()將調用Action執行。app

 流程結構圖:框架

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以後,攔截器的執行順序與堆棧中定義的順序相反。2、Interceptor攔截類型 this

2、Interceptor攔截類型

  從上面的分析,咱們知道,整個攔截器的核心部分是invocation.invoke()這個函數的調用位置。事實上,咱們也正式根據這句代碼的調用位置,來進行攔截類型的區分的。在Struts2中,Interceptor的攔截類型,分紅如下三類: 
  一、 before 
  before攔截,是指在攔截器中定義的代碼,它們存在於invocation.invoke()代碼執行以前。這些代碼,將依照攔截器定義的順序,順序執行。 
  二、 after 
  after攔截,是指在攔截器中定義的代碼,它們存在於invocation.invoke()代碼執行以後。這些代碼,將一招攔截器定義的順序,逆序執行。spa

  三、PreResultListener .net

  有的時候,before攔截和after攔截對咱們來講是不夠的,由於咱們須要在Action執行完以後,可是尚未回到視圖層以前,作一些事情。Struts2一樣支持這樣的攔截,這種攔截方式,是經過在攔截器中註冊一個PreResultListener的接口來實現的。如:在攔截器中使用以下代碼,其中MyPreResultListener實現了PreResultListener 接口並在beforeResult方法中作了一些事情而後在攔截器類中加入code

action.addPreResultListener(new MyPreResultListener());

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

3、問題

  使用Struts2做爲web框架,知道它的攔截器(Interceptor)機制,相似與Filter和Spring的AOP,因而實現了一個爲Action增長自定義前置(before)動做和後置動做(after)的攔截器(曰:WInterceptor),不過用一段時間發現,在WInterceptor的after中,對Action對象的屬性修改在頁面看不到,對請求對象的屬性設置也無效。爲何在調用了Action以後(invokeAction())以後,request就不能使用了呢,攔截器不能改變Action的Result麼?blog

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

解決辦法:

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

  搞清楚緣由,捲起袖子幹吧,只要讓WInterpretor的after事件,放在Result的生成以前就好了。看看XWork的攔截器接口注入的actionInvocation,其實就提供增長Result執行的前置監聽事件-PreResultListener:

void addPreResultListener(PreResultListener listener);

  所以,讓攔截器實現這個接口,就能夠天然實現Action執行after事件了。

  方法二:實現本身的 ActionInvocation ,手動分離Action和Result的執行

  原本前面的方法已經很好了,但是在addPreResultListener裏的異常,不會被Struts的框架捕獲,並且addPreResultListener接口不能傳遞本身的上下文參數,難道動用ThreadLocal傳參?研究了一下XWork的ActionInvocation 接口默認實現類DefaultActionInvocation,能夠 寫了一個包裝類,將Action的執行和Result的生成徹底分開。exeucteAction是執行Action,executeResult是執行Result。

 

轉載於https://blog.csdn.net/xuchuangqi/article/details/53248306

相關文章
相關標籤/搜索