java 設計模式 攔截器

攔截器(interceptor)是Struts2最強大的特性之一,也可以說是struts2的核心,攔截器可以讓你在Action和result被執行之前或之後進行一些處理。同時,攔截器也可以讓你將通用的代碼模塊化並作爲可重用的類。Struts2中的很多特性都是由攔截器來完成的。攔截是AOP的一種實現策略。在Webwork的中文文檔的解釋爲:攔截器是動態攔截Action調用的對象。它提供了一種機制可以使開發者可以定義在一個action執行的前後執行的代碼,也可以在一個action執行前阻止其執行。同時也是提供了一種可以提取action中可重用的部分的方式。談到攔截器,還有一個詞大家應該知道——攔截器鏈(Interceptor
Chain,在Struts 2中稱爲攔截器棧Interceptor
Stack)。攔截器鏈就是將攔截器按一定的順序聯結成一條鏈。在訪問被攔截的方法或字段時,攔截器鏈中的攔截器就會按其之前定義的順序被調用

爲了便於自身理解,我們自己實現一個。
在我們的請求到來之前,加入現在我進入了一個頁面,而改頁面是需要先檢查是否已登錄,此時如果我加一個判斷的話,就可以很容易實現,但是當我們的頁面增多時,那麼就該爲我們的每個請求頁面都加個判斷,是相當麻煩的一件事,故此,spring或struts都爲我們提供了相應的攔截器,以下是攔截器的實現原理:
這裏寫圖片描述

首先我們需要定義一個action接口

public interface Action {
    String execute();
}

攔截器接口

public interface Interceptor {  
    void before(ActionInvocation invocation);
    String intercept(ActionInvocation invocation);
    void after(ActionInvocation invocation);
}

調度器接口

public interface ActionInvocation {
    String invoke();
}

定義我們的攔截器

AroundInterceptor 攔截器

package com.cmh.intercept;

import com.cmh.service.ActionInvocation;

public class AroundInterceptor implements Interceptor{

    @Override
    public void before(ActionInvocation invocation) {
        // TODO Auto-generated method stub
        System.out.println("before:"+"AroundInterceptor");
    }

    @Override
    public String intercept(ActionInvocation invocation) {
        // TODO Auto-generated method stub
        before(invocation);
        String result = invocation.invoke();
        after(invocation);
        return result;
    }

    @Override
    public void after(ActionInvocation invocation) {
        // TODO Auto-generated method stub
        System.out.println("after:"+"AroundInterceptor");
    }
}

ExceptionInterceptor攔截器

package com.cmh.intercept;

import com.cmh.service.ActionInvocation;

public class ExceptionInterceptor implements Interceptor{

    @Override
    public void before(ActionInvocation invocation) {
        // TODO Auto-generated method stub
        System.out.println("before:"+"ExceptionInterceptor");
    }

    @Override
    public String intercept(ActionInvocation invocation) {
        // TODO Auto-generated method stub
        before(invocation);
        String result = invocation.invoke();
        after(invocation);
        return result;
    }

    @Override
    public void after(ActionInvocation invocation) {
        // TODO Auto-generated method stub
        System.out.println("after:"+"ExceptionInterceptor");
    }
}

I18NInterceptor攔截器

package com.cmh.intercept;

import com.cmh.service.ActionInvocation;

public class I18NInterceptor implements Interceptor{

    @Override
    public void before(ActionInvocation invocation) {
        // TODO Auto-generated method stub
        System.out.println("before:"+"I18NInterceptor");
    }

    @Override
    public String intercept(ActionInvocation invocation) {
        // TODO Auto-generated method stub
        before(invocation);
        String result = invocation.invoke();
        after(invocation);
        return result;
    }

    @Override
    public void after(ActionInvocation invocation) {
        // TODO Auto-generated method stub
        System.out.println("after:"+"I18NInterceptor");
    }
}

調度器實現類DefaultActionInvoation

package com.cmh.service;

import java.util.ArrayList;
import java.util.List;

import com.cmh.action.Action;
import com.cmh.intercept.Interceptor;

public class DefaultActionInvoation implements ActionInvocation{

    int index = 0;

    private Action action; 

    private List<Interceptor> interceptors = new ArrayList<Interceptor>();



    /**
     * Get action   
     * @return Action the action
     */
    public Action getAction() {
        return action;
    }

    /**
     * Set action
     * @param action Action the action to set
     */
    public void setAction(Action action) {
        this.action = action;
    }


    /**
     * Set interceptors
     * @param interceptors List<Interceptor> the interceptors to set
     */
    public void addInterceptor(Interceptor interceptors) {
        this.interceptors.add(interceptors);
    }



    @Override
    public String invoke() {//遞歸調用
        // TODO Auto-generated method stub
        String result = ""; 
        if(index == interceptors.size()){
            result = action.execute();
        }else{
            Interceptor interceptor =interceptors.get(index);
            index++;
            result = interceptor.intercept(this);
        }
        return result;
    }

}

測試類

public static void test3(){
        Interceptor exptionInterceptor = new ExceptionInterceptor();  
        Interceptor i18nInterceptor = new I18NInterceptor();  
        Interceptor aroundInterceptor = new AroundInterceptor();  

        DefaultActionInvoation actionInvocation = new DefaultActionInvoation();  
        actionInvocation.addInterceptor(exptionInterceptor);  
        actionInvocation.addInterceptor(i18nInterceptor);  
        actionInvocation.addInterceptor(aroundInterceptor);  


        Action action = new HelloWorldAction();  
        actionInvocation.setAction(action);  

        String result = actionInvocation.invoke();  
        System.out.println("Action result:" + result); 
    }

測試結果
這裏寫圖片描述

由以上代碼不難看出,當我們的請求來到時,首先會經DefaultActionInvoation 的invoke處理,調用的次序依次爲
ExceptionInterceptor->I18NInterceptor->AroundInterceptor->AroundInterceptor->I18NInterceptor->ExceptionInterceptor
最後纔將我們的結果給弄出來,以上爲一個攔截器最基本的原理。下面我們來看看struts2中的原代碼及流程

strtus2的流程圖
這裏寫圖片描述

我們再來看看他的源代碼

以下是DefaultActionInvoation 中的invoke的源代碼

/** 

 * @throws ConfigurationException If no result can be found with the returned code 

 */  

public String invoke() throws Exception {  

    String profileKey = "invoke: ";  

    try {  

     UtilTimerStack.push(profileKey);  



     if (executed) {  

     throw new IllegalStateException("Action has already executed");  

     }  

        // 依次調用攔截器堆棧中的攔截器代碼執行  

     if (interceptors.hasNext()) {  

     final InterceptorMapping interceptor = (InterceptorMapping) interceptors.next();  

     UtilTimerStack.profile("interceptor: "+interceptor.getName(),   

     new UtilTimerStack.ProfilingBlock<String>() {  

public String doProfiling() throws Exception {  

                         // 將ActionInvocation作爲參數,調用interceptor中的intercept方法執行  

     resultCode = interceptor.getInterceptor().intercept(DefaultActionInvocation.this);  

     return null;  

}  

     });  

     } else {  

     resultCode = invokeActionOnly();  

     }  


     // this is needed because the result will be executed, then control will return to the Interceptor, which will  

     // return above and flow through again  

     if (!executed) {  

            // 執行PreResultListener  

     if (preResultListeners != null) {  

     for (Iterator iterator = preResultListeners.iterator();  

     iterator.hasNext();) {  

     PreResultListener listener = (PreResultListener) iterator.next();  



     String _profileKey="preResultListener: ";  

     try {  

     UtilTimerStack.push(_profileKey);  

     listener.beforeResult(this, resultCode);  

     }  

     finally {  

     UtilTimerStack.pop(_profileKey);  

     }  

     }  

     }  


     // now execute the result, if we're supposed to  

            // action與interceptor執行完畢,執行Result  

     if (proxy.getExecuteResult()) {  

     executeResult();  

     }  


     executed = true;  

     }  


     return resultCode;  

    }  

    finally {  

     UtilTimerStack.pop(profileKey);  

    }  

}  

攔截器的源代碼

public String intercept(ActionInvocation invocation) throws Exception {  

String result = null;  


        before(invocation);  

        // 調用下一個攔截器,如果攔截器不存在,則執行Action  

        result = invocation.invoke();  

        after(invocation, result);  


        return result;  

}  

struts的攔截器最大歸功於他的動態代理模式,因爲我們的action具體類都是一個繼承動態代理的類。所以這就不必爲每一個類都加相應的邏輯,只需繼承就行了。

發佈了89 篇原創文章 · 獲贊 44 · 訪問量 15萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章