struts2-invocation


[轉載]       

“將Web頁面中的輸入元素封裝為一個(請求)數據對象”,這個對象就是ActionInvocation類型.
        對於Xwork 而言,前端的Webwork 組件為其提供的是一個Map 類型的數據結構。而Action面向的卻是Model對象所提供的數據結構。在何時、何處對這兩種不同的數據結構進行轉換?
        寫一個輔助類完成這樣的工作,並在每次Action 調用之前由框架代碼調用他完成轉換工作。
Xwork 通過Interceptor 實現了這一步驟,從而我們可以根據需要,靈活的配置所需的Interceptor。從而為Action提供可擴展的預處理、后處理過程。

          ActionInvocation 是Xworks 中Action 調度的核心。而對Interceptor 的調度,也正是由ActionInvocation負責。
         ActionInvocation 是一個接口, 而DefaultActionInvocation 則是Webwork 對ActionInvocation的默認實現。

      Interceptor 的調度流程大致如下:

      1. ActionInvocation初始化時,根據配置,加載Action相關的所有Interceptor。

      參見ActionInvocation.init方法中相關代碼:
     

private   void  init()  throws  Exception  {
……
List interceptorList 
= new
ArrayList(proxy.getConfig().getInterceptors());
interceptors 
= interceptorList.iterator();



   2. 通過ActionInvocation.invoke方法調用Action實現時,執行Interceptor:
       下面是DefaultActionInvocation中Action調度代碼:

public  String invoke()  throws  Exception  {
    
if (executed)
        
throw new IllegalStateException("Action has already executed");
    
if (interceptors.hasNext()) {
        Interceptor interceptor 
= (Interceptor) interceptors.next();
        resultCode 
= interceptor.intercept(this);
    }
 else
        resultCode 
= invokeAction(getAction(), proxy.getConfig());
    
if (!executed) {
        
if (preResultListeners != null{
        Iterator iterator 
= preResultListeners.iterator();
        
while (iterator.hasNext()) {
            PreResultListener listener
            
= (PreResultListener) iterator.next();
            listener.beforeResult(
this, resultCode);
        }

        }

        
if (proxy.getExecuteResult())
        executeResult();
        executed 
= true;
    }

    
return resultCode;
    }

    



所有的攔截器都必須實現Interceptor 接口。

      public interface Interceptor {
         void destroy();
         void init();
         String intercept(ActionInvocation invocation) throws Exception;
     }
     在Interceptor 實現中,抽象實現AroundInterceptor得到了最廣泛的應用(擴展),它增加了預處理(before)和后處理(after)方法的定義。

     AroundInterceptor.java:

public   abstract   class  AroundInterceptor  implements  Interceptor
{
    
protected Log log = LogFactory.getLog(this.getClass());
    
    
public void destroy() {
    }

    
    
public void init() {
    }

    
    
public String intercept(ActionInvocation invocation) throws Exception {
    String result 
= null;
    before(invocation);
    result 
= invocation.invoke();
    after(invocation, result);
    
return result;
    }

    
    
protected abstract void after
    (ActionInvocation actioninvocation, String string) 
throws Exception;
    
    
protected abstract void before(ActionInvocation actioninvocation)
    
throws Exception;
}


    AroundInterceptor.invoke 方法中,調用了參數invocation的invoke 方法。

 最后,結合最常用的ParametersInterceptor,看看Xwork 是如何通過Interceptor,將Webwork傳入的Map類型數據結構,轉換為Action所需的Java 模型對象。

   ParametersInterceptor.java:

public   class  ParametersInterceptor  extends  AroundInterceptor  {
protected void after(ActionInvocation dispatcher, String result)
throws Exception {
}

protected void before(ActionInvocation invocation) throws Exception
{
if (!(invocation.getAction() instanceof NoParameters)) {
final Map parameters =
ActionContext.getContext().getParameters(); ⑴
if (log.isDebugEnabled()) {
log.debug(
"Setting params " + parameters);
}

ActionContext invocationContext 
=
invocation.getInvocationContext();
try {
invocationContext.put(
InstantiatingNullHandler.CREATE_NULL_OBJECTS,
Boolean.TRUE);
invocationContext.put(
XWorkMethodAccessor.DENY_METHOD_EXECUTION,
Boolean.TRUE);
invocationContext.put(
XWorkConverter.REPORT_CONVERSION_ERRORS,
Boolean.TRUE);
if (parameters != null{
final OgnlValueStack stack =
ActionContext.getContext().getValueStack(); ⑵
for (Iterator iterator =parameters.entrySet().iterator();
iterator.hasNext();
{
Map.Entry entry 
= (Map.Entry) iterator.next();
stack.setValue( ⑷
entry.getKey().toString(),
entry.getValue());
}

}

}
 finally {
invocationContext.put(
InstantiatingNullHandler.CREATE_NULL_OBJECTS,
Boolean.FALSE);
invocationContext.put(
XWorkMethodAccessor.DENY_METHOD_EXECUTION,
Boolean.FALSE);
invocationContext.put(
XWorkConverter.REPORT_CONVERSION_ERRORS,
Boolean.FALSE);
}

}

}

}



ParametersInterceptor 擴展了抽象類AroundInterceptor。並在其預處理方法(before)中實現了數據的轉換。
數據轉換的過程並不復雜:
⑴ 首先由ActionContext獲得Map型的參數集parameters。
⑵ 由ActionContext獲得值棧(OgnlValueStack)。
⑶ 遍歷parameters中的各項數據。
⑷ 通過OgnlValueStack,根據數據的鍵值,為Model 對象填充屬性數據。
OgnlValueStack 是http://www.ognl.org4提供的一套可讀寫對象屬性的類庫

上面的代碼中並沒有發現將Model對象入棧的部分,是由於ActionInvocation在初始化的時候已經預先完成了壓棧工作,如DefaultActionInvocation.init方法中代碼所示:

private void init() throws Exception {
Map contextMap = createContextMap();
createAction();
if (pushAction) {
stack.push(action);      //壓棧
}
……


旁白:Servlet 2.3規范中引入的Filter 算是攔截器的一個典型實現,它在Servlet執行之前被觸發,對輸入參數進行處理之后,再將工作流程傳遞給對應的Servlet。


免責聲明!

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



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