1. 程式人生 > >設計模式(13)--Chain of Responsibility(責任鏈模式)--行為型

設計模式(13)--Chain of Responsibility(責任鏈模式)--行為型

sse 之前 對象 接收 高級 組裝 的人 exe 必須

1.模式定義:

  責任鏈模式是一種對象的行為模式。在責任鏈模式裏,很多對象由每一個對象對其下家的引用而連接起來形成一條鏈。請求在這個鏈上傳遞,直到鏈上的某一個對象決定處理此請求。發出這個請求的客戶端並不知道鏈上的哪一個對象最終處理這個請求,這使得系統可以在不影響客戶端的情況下動態地重新組織和分配責任。

2.模式特點:

  責任鏈模式通過建立一條鏈來組織請求的處理者,請求將沿著鏈進行傳遞,請求發送者無須知道請求在何時、何處以及如何被處理,實現了請求發送者與處理者的解耦。在軟件開發中,如果遇到有多個對象可以處理同一請求時可以應用責任鏈模式,例如在Web應用開發中創建一個過濾器(Filter)鏈來對請求數據進行過濾,在工作流系統中實現公文的分級審批等等,使用責任鏈模式可以較好地解決此類問題。   另外:責任鏈模式其實就是一個靈活版的if…else…語句,它就是將這些判定條件的語句放到了各個處理類中,這樣做的優點是比較靈活了,但同樣也帶來了風險,比如設置處理類前後關系時,一定要特別仔細,搞對處理類前後邏輯的條件判斷關系,並且註意不要在鏈中出現循環引用的問題。 責任鏈模式的要點主要是:
  (1)有多個對象共同對一個任務進行處理。   (2)這些對象使用鏈式存儲結構,形成一個鏈,每個對象知道自己的下一個對象。   (3)一個對象對任務進行處理,可以添加一些操作後將對象傳遞個下一個任務。也可以在此對象上結束任務的處理,並結束任務。   (4)客戶端負責組裝鏈式結構,但是客戶端不需要關心最終是誰來處理了任務。

3.使用場景:

  (1)有多個對象可以處理同一個請求,但是具體由哪個對象來處理該請求,是運行時刻動態確定的。這種情況可以使用責任鏈模式,把處理請求的對象實現成為責任對象,然後把它們構成一個責任鏈,當請求在這個鏈中傳遞的時候,具體由哪個責任對象來處理,會在運行時動態判斷。   (2)你想在不明確指定接收者的情況下,向多個對象中的一個提交一個請求的話,可以使用責任鏈模式,責任鏈模式實現了請求者和接收者之間的解耦,請求者不需要知道究竟是哪一個接收者對象來處理了請求。   (3)想要動態指定處理一個請求的對象集合,可以使用責任鏈模式,責任鏈模式能動態的構建責任鏈,也就是動態的來決定到底哪些責任對象來參與到處理請求中來,相當於是動態指定了處理一個請求的責任對象集合。   (4)使用if…else…語句,代碼看上去很糟糕時,就可以使用責任鏈模式實現。

4.模式實現:

   下面使用了一個責任鏈模式的最簡單的實現。 技術分享 責任鏈模式涉及到的角色如下所示:

 (1)抽象處理者(Handler)角色:

  定義出一個處理請求的接口。如果需要,接口可以定義 出一個方法以設定和返回對下家的引用。這個角色通常由一個Java抽象類或者Java接口實現。上圖中Handler類的聚合關系給出了具體子類對下家的引用,抽象方法handleRequest()規範了子類處理請求的操作。
public abstract class Handler {
    /**
     * 持有後繼的責任對象
     */
    protected Handler successor;
    
/** * 示意處理請求的方法,雖然這個示意方法是沒有傳入參數的 * 但實際是可以傳入參數的,根據具體需要來選擇是否傳遞參數 */ public abstract void handleRequest(); /** * 取值方法 */ public Handler getSuccessor() { return successor; } /** * 賦值方法,設置後繼的責任對象 */ public void setSuccessor(Handler successor) { this.successor = successor; } }

 (2)具體處理者(ConcreteHandler)角色:

  具體處理者接到請求後,可以選擇將請求處理掉,或者將請求傳給下家。由於具體處理者持有對下家的引用,因此,如果需要,具體處理者可以訪問下家。
public class ConcreteHandler extends Handler {
    /**
     * 處理方法,調用此方法處理請求
     */
    @Override
    public void handleRequest() {
        /**
         * 判斷是否有後繼的責任對象
         * 如果有,就轉發請求給後繼的責任對象
         * 如果沒有,則處理請求
         */
        if(getSuccessor() != null)
        {            
            System.out.println("放過請求");
            getSuccessor().handleRequest();            
        }else
        {            
            System.out.println("處理請求");
        }
    }
}

  (3)客戶端類

public class Client {
    public static void main(String[] args) {
        //組裝責任鏈
        Handler handler1 = new ConcreteHandler();
        Handler handler2 = new ConcreteHandler();
        handler1.setSuccessor(handler2);
        //提交請求
        handler1.handleRequest();
    }
}
  可以看出,客戶端創建了兩個處理者對象,並指定第一個處理者對象的下家是第二個處理者對象,而第二個處理者對象沒有下家。然後客戶端將請求傳遞給第一個處理者對象。   由於本示例的傳遞邏輯非常簡單:只要有下家,就傳給下家處理;如果沒有下家,就自行處理。因此,第一個處理者對象接到請求後,會將請求傳遞給第二個處理者對象。由於第二個處理者對象沒有下家,於是自行處理請求。活動時序圖如下所示。 技術分享

5.優缺點:

(1)責任鏈模式的優點:

     [1]請求者和接收者松散耦合:在責任鏈模式裏面,請求者並不知道接收者是誰,也不知道具體如何處理,請求者只是負責向責任鏈發出請求就可以了。而每個責任對象也不用管請求者或者是其它的責任對象,只負責處理自己的部分,其它的就交由其它的責任對象去處理。也就是說,請求者和接收者是完全解耦的。     [2]動態組合責任:責任鏈模式會把功能處理分散到單獨的責任對象裏面,然後在使用的時候,可以動態組合責任形成責任鏈,從而可以靈活的給對象分配責任,也可以靈活的實現和改變對象的責任。     [3]簡化了對象:請求處理對象僅需維持一個指向其後繼者的引用,而不需要維持它對所有的候選處理者的引用,可簡化對象的相互連接。     [4]增加新的請求處理類很方便:在系統中增加一個新的具體請求處理者時無須修改原有系統的代碼,只需要在客戶端重新建鏈即可,從這一點來看是符合“開閉原則”的。

  (2)責任鏈模式的缺點:

    [1]產生很多細粒度對象:責任鏈模式會把功能處理分散到單獨的責任對象裏面,也就是每個責任對象只是處理一個方面的功能,要把整個業務處理完,需要大量的責任對象的組合,這會產生大量的細粒度責任對象。     [2]不一定能被處理:責任鏈模式的每個責任對象只負責自己處理的那一部分,因此可能會出現某個請求,把整個鏈傳遞完了,都沒有責任對象處理它。這就需要在使用責任鏈模式的時候註意,需要提供默認的處理,並且註意構建的鏈的有效性。     [3]可能造成循環調用:如果建鏈不當,可能會造成循環調用,將導致系統陷入死循環。     [4]調試不方便:對於比較長的責任鏈,請求的處理可能涉及到多個處理對象,在進行代碼調試時不太方便,有礙於除錯。     [5]不能保證請求一定被接收:既然一個請求沒有明確的接收者,那麽就不能保證它一定會被處理 —該請求可能一直到鏈的末端都得不到處理。一個請求也可能因該鏈沒有被正確配置而得不到處理。     [6] 系統性能將受到一定影響:而且在進行代碼調試時不太方便;可能會造成循環調用。

6. 純與不純的責任鏈模式

  (1)純的責任鏈模式:

  一個具體處理者角色處理只能對請求作出兩種行為中的一個:一個是自己處理(承擔責任),另一個是把責任推給下家。不允許出現某一個具體處理者對象在承擔了一部分責任後又將責任向下傳的情況。請求在責任鏈中必須被處理,不能出現無果而終的結局。

  (2)反之就是不純的責任鏈模式。

  在一個純的責任鏈模式裏面,一個請求必須被某一個處理者對象所接收;在一個不純的責任鏈模式裏面,一個請求可以最終不被任何接收端對象所接收。

7.責任鏈模式與狀態模式對比

  狀態模式也好,責任鏈模式也罷,都能解耦和優化大量的邏輯判斷,如:if…else…語句。   責任鏈模式使多個對象都有機會處理請求,從而避免請求的發送者和接受者之間的耦合關系。將這個對象練成一條鏈,並沿著這條鏈傳遞該請求,直到有一個對象處理它為止。各個責任類不知道也沒必要知道下一個責任對象是誰!由客戶端統一設置順序和誰連接到鏈條,誰不連接到鏈條…… 可以看出,責任鏈在client(客戶端)連接,責任鏈模式要比狀態模式靈活很多。   但是,這時候有人要問,既然他們都可以解決邏輯判斷的分支過多的問題,那麽,是不是責任鏈模式比狀態模式好呢?   責任鏈模式過於靈活,在客戶端使用時,需要客戶端去確定下一個對象是誰,一些列的set操作…… 在多次設置的時候很容易出問題。   另外狀態模式是一個對象的內在狀態發生改變,而責任鏈模式是多個對象之間的改變,這也說明他們兩個模式處理的情況不同。 小結:   個人認為,責任鏈模式與狀態模式的最大的不同是設置自己的下一級的問題上,狀態模式是在類的設計階段就定好的,不能在客戶端改變,而責任鏈的下一級是在客戶端自己來確定的。   狀態模式:是讓各個狀態對象自己知道其下一個處理的對象是誰,即在編譯時便設定。相當於If ,else-if,else-if……, 設計思路是把邏輯判斷轉移到各個State類的內部實現(相當於If,else If),執行時客戶端通過調用環境—Context類的方法來間接執行狀態類的行為,客戶端不直接和狀態交互。   責任鏈模式:各個對象並不指定其下一個處理的對象到底是誰,只有在客戶端才設定某個類型的鏈條,請求發出後穿越鏈條,直到被某個責任類處理或者鏈條結束。設計思路是把各個業務邏輯判斷封裝到不同責任類,且攜帶下一個責任的對應引用,但不像狀態模式那樣需要明確知道這個引用指向誰,而是在客戶端設置鏈接方式或者過程。使用時,向鏈的第一個子類的執行方法傳遞參數就可以。客戶端去通過環境類調用責任鏈,全自動運轉起來。

8.註意事項

  在責任鏈模式裏,很多對象由每一個對象對其下家的引用而連接起來形成一條鏈。請求在這個鏈上傳遞,直到鏈上的某一個對象決定處理此請求。發出這個請求的客戶端並不知道鏈上的哪一個對象最終處理這個請求,這使得系統可以在不影響客戶端的情況下動態地重新組織鏈和分配責任。   責任鏈模式的主要優點在於可以降低系統的耦合度,簡化對象的相互連接,同時增強給對象指派責任的靈活性,增加新的請求處理類也很方便;其主要缺點在於不能保證請求一定被接收,且對於比較長的責任鏈,請求的處理可能涉及到多個處理對象,系統性能將受到一定影響,而且在進行代碼調試時不太方便。

9.應用實例

(1)JAVA WEB 中 Apache Tomcat 對 Encoding 的處理, (2)Java中的異常機制就是一種責任鏈模式,catch鏈就是一種責任鏈。 (3)JavaScript中的時間冒泡和捕獲機制。 (4)Servlet中的過濾器的鏈式處理。 (5)Structs2中攔截器的調用。 (6)Tomcat中的Filter就是使用了責任鏈模式,還有Tomcat中Valve鏈...

10.代碼實例:

  來考慮這樣一個功能:申請聚餐費用的管理。     很多公司都是這樣的福利,就是項目組或者是部門可以向公司申請一些聚餐費用,用於組織項目組成員或者是部門成員進行聚餐活動。     申請聚餐費用的大致流程一般是:由申請人先填寫申請單,然後交給領導審批,如果申請批準下來,領導會通知申請人審批通過,然後申請人去財務領取費用,如果沒有批準下來,領導會通知申請人審批未通過,此事也就此作罷。     不同級別的領導,對於審批的額度是不一樣的,比如,項目經理只能審批500元以內的申請;部門經理能審批1000元以內的申請;而總經理可以審核任意額度的申請。     也就是說,當某人提出聚餐費用申請的請求後,該請求會經由項目經理、部門經理、總經理之中的某一位領導來進行相應的處理,但是提出申請的人並不知道最終會由誰來處理他的請求,一般申請人是把自己的申請提交給項目經理,或許最後是由總經理來處理他的請求。       可以使用責任鏈模式來實現上述功能:當某人提出聚餐費用申請的請求後,該請求會在 項目經理-->部門經理-->總經理 這樣一條領導處理鏈上進行傳遞,發出請求的人並不知道誰會來處理他的請求,每個領導會根據自己的責任範圍,來判斷是處理請求還是把請求交給更高級別的領導,只要有領導處理了,傳遞就結束了。     需要把每位領導的處理獨立出來,實現成單獨的責任處理對象,然後為它們提供一個公共的、抽象的父責任對象,這樣就可以在客戶端來動態地組合責任鏈,實現不同的功能要求了。 技術分享

  (1)抽象處理者角色類

public abstract class Handler {
    /**
     * 持有下一個處理請求的對象
     */
    protected Handler successor = null;
    /**
     * 取值方法
     */
    public Handler getSuccessor() {
        return successor;
    }
    /**
     * 設置下一個處理請求的對象
     */
    public void setSuccessor(Handler successor) {
        this.successor = successor;
    }
    /**
     * 處理聚餐費用的申請
     * @param user    申請人
     * @param fee    申請的錢數
     * @return        成功或失敗的具體通知
     */
    public abstract String handleFeeRequest(String user , double fee);
}

  (2)具體處理者角色

public class ProjectManager extends Handler {
    @Override
    public String handleFeeRequest(String user, double fee) {        
        String str = "";
        //項目經理權限比較小,只能在500以內
        if(fee < 500)
        {
            //為了測試,簡單點,只同意張三的請求
            if("張三".equals(user))
            {
                str = "成功:項目經理同意【" + user + "】的聚餐費用,金額為" + fee + "元";    
            }else
            {
                //其他人一律不同意
                str = "失敗:項目經理不同意【" + user + "】的聚餐費用,金額為" + fee + "元";
            }
        }else
        {
            //超過500,繼續傳遞給級別更高的人處理
            if(getSuccessor() != null)
            {
                return getSuccessor().handleFeeRequest(user, fee);
            }
        }
        return str;
    }

}
public class DeptManager extends Handler {
    @Override
    public String handleFeeRequest(String user, double fee) {
        
        String str = "";
        //部門經理的權限只能在1000以內
        if(fee < 1000)
        {
            //為了測試,簡單點,只同意張三的請求
            if("張三".equals(user))
            {
                str = "成功:部門經理同意【" + user + "】的聚餐費用,金額為" + fee + "元";    
            }else
            {
                //其他人一律不同意
                str = "失敗:部門經理不同意【" + user + "】的聚餐費用,金額為" + fee + "元";
            }
        }else
        {
            //超過1000,繼續傳遞給級別更高的人處理
            if(getSuccessor() != null)
            {
                return getSuccessor().handleFeeRequest(user, fee);
            }
        }
        return str;
    }

}
public class GeneralManager extends Handler {
    @Override
    public String handleFeeRequest(String user, double fee) {
        
        String str = "";
        //總經理的權限很大,只要請求到了這裏,他都可以處理
        if(fee >= 1000)
        {
            //為了測試,簡單點,只同意張三的請求
            if("張三".equals(user))
            {
                str = "成功:總經理同意【" + user + "】的聚餐費用,金額為" + fee + "元";    
            }else
            {
                //其他人一律不同意
                str = "失敗:總經理不同意【" + user + "】的聚餐費用,金額為" + fee + "元";
            }
        }else
        {
            //如果還有後繼的處理對象,繼續傳遞
            if(getSuccessor() != null)
            {
                return getSuccessor().handleFeeRequest(user, fee);
            }
        }
        return str;
    }

}

  (3)客戶端類

public class Client {
    public static void main(String[] args) {
        //先要組裝責任鏈
        Handler h1 = new GeneralManager();
        Handler h2 = new DeptManager();
        Handler h3 = new ProjectManager();
        h3.setSuccessor(h2);
        h2.setSuccessor(h1);
        
        //開始測試
        String test1 = h3.handleFeeRequest("張三", 300);
        System.out.println("test1 = " + test1);
        String test2 = h3.handleFeeRequest("李四", 300);
        System.out.println("test2 = " + test2);
        System.out.println("---------------------------------------");
        
        String test3 = h3.handleFeeRequest("張三", 700);
        System.out.println("test3 = " + test3);
        String test4 = h3.handleFeeRequest("李四", 700);
        System.out.println("test4 = " + test4);
        System.out.println("---------------------------------------");
        
        String test5 = h3.handleFeeRequest("張三", 1500);
        System.out.println("test5 = " + test5);
        String test6 = h3.handleFeeRequest("李四", 1500);
        System.out.println("test6 = " + test6);
    }

}
運行結果如下所示: 技術分享

11.責任鏈模式在Tomcat中的應用

  眾所周知Tomcat中的Filter就是使用了責任鏈模式,創建一個Filter除了要在web.xml文件中做相應配置外,還需要實現javax.servlet.Filter接口。
public class TestFilter implements Filter{
    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {
        chain.doFilter(request, response);
    }
    public void destroy() {
    }
    public void init(FilterConfig filterConfig) throws ServletException {
    }
}
使用DEBUG模式所看到的結果如下: 技術分享  其實在真正執行到TestFilter類之前,會經過很多Tomcat內部的類。順帶提一下其實Tomcat的容器設置也是責任鏈模式,註意被紅色方框所圈中的類,從Engine到Host再到Context一直到Wrapper都是通過一個鏈傳遞請求。被綠色方框所圈中的地方有一個名為ApplicationFilterChain的類,ApplicationFilterChain類所扮演的就是抽象處理者角色,而具體處理者角色由各個Filter扮演。

  (1)第一個疑問是ApplicationFilterChain將所有的Filter存放在哪裏?

答案是保存在ApplicationFilterChain類中的一個ApplicationFilterConfig對象的數組中。
   /**
     * Filters.
     */
    private ApplicationFilterConfig[] filters =  new ApplicationFilterConfig[0];

  (2)那ApplicationFilterConfig對象又是什麽呢?

ApplicationFilterConfig是一個Filter容器。以下是ApplicationFilterConfig類的聲明:
/**
 * Implementation of a <code>javax.servlet.FilterConfig</code> useful in
 * managing the filter instances instantiated when a web application
 * is first started.
 *
 * @author Craig R. McClanahan
 * @version $Id: ApplicationFilterConfig.java 1201569 2011-11-14 01:36:07Z kkolinko $
 */
  當一個web應用首次啟動時ApplicationFilterConfig會自動實例化,它會從該web應用的web.xml文件中讀取配置的Filter的信息,然後裝進該容器。

  (3)剛剛看到在ApplicationFilterChain類中所創建的ApplicationFilterConfig數組長度為零,那它是在什麽時候被重新賦值的呢?

 private ApplicationFilterConfig[] filters =  new ApplicationFilterConfig[0];
  是在調用ApplicationFilterChain類的addFilter()方法時。
    /**
     * The int which gives the current number of filters in the chain.
     */
    private int n = 0;
    public static final int INCREMENT = 10;
調用:
    void addFilter(ApplicationFilterConfig filterConfig) {

        // Prevent the same filter being added multiple times
        for(ApplicationFilterConfig filter:filters)
            if(filter==filterConfig)
                return;

        if (n == filters.length) {
            ApplicationFilterConfig[] newFilters =
                new ApplicationFilterConfig[n + INCREMENT];
            System.arraycopy(filters, 0, newFilters, 0, n);
            filters = newFilters;
        }
        filters[n++] = filterConfig;

    }
  變量n用來記錄當前過濾器鏈裏面擁有的過濾器數目,默認情況下n等於0,ApplicationFilterConfig對象數組的長度也等於0,所以當第一次調用addFilter()方法時,if (n ==filters.length)的條件成立,ApplicationFilterConfig數組長度被改變。之後filters[n++] = filterConfig;將變量filterConfig放入ApplicationFilterConfig數組中並將當前過濾器鏈裏面擁有的過濾器數目+1。

  (4)那ApplicationFilterChain的addFilter()方法又是在什麽地方被調用的呢?

  是在ApplicationFilterFactory類的createFilterChain()方法中。
  1 public ApplicationFilterChain createFilterChain
  2         (ServletRequest request, Wrapper wrapper, Servlet servlet) {
  3 
  4         // get the dispatcher type
  5         DispatcherType dispatcher = null; 
  6         if (request.getAttribute(DISPATCHER_TYPE_ATTR) != null) {
  7             dispatcher = (DispatcherType) request.getAttribute(DISPATCHER_TYPE_ATTR);
  8         }
  9         String requestPath = null;
 10         Object attribute = request.getAttribute(DISPATCHER_REQUEST_PATH_ATTR);
 11         
 12         if (attribute != null){
 13             requestPath = attribute.toString();
 14         }
 15         
 16         // If there is no servlet to execute, return null
 17         if (servlet == null)
 18             return (null);
 19 
 20         boolean comet = false;
 21         
 22         // Create and initialize a filter chain object
 23         ApplicationFilterChain filterChain = null;
 24         if (request instanceof Request) {
 25             Request req = (Request) request;
 26             comet = req.isComet();
 27             if (Globals.IS_SECURITY_ENABLED) {
 28                 // Security: Do not recycle
 29                 filterChain = new ApplicationFilterChain();
 30                 if (comet) {
 31                     req.setFilterChain(filterChain);
 32                 }
 33             } else {
 34                 filterChain = (ApplicationFilterChain) req.getFilterChain();
 35                 if (filterChain == null) {
 36                     filterChain = new ApplicationFilterChain();
 37                     req.setFilterChain(filterChain);
 38                 }
 39             }
 40         } else {
 41             // Request dispatcher in use
 42             filterChain = new ApplicationFilterChain();
 43         }
 44 
 45         filterChain.setServlet(servlet);
 46 
 47         filterChain.setSupport
 48             (((StandardWrapper)wrapper).getInstanceSupport());
 49 
 50         // Acquire the filter mappings for this Context
 51         StandardContext context = (StandardContext) wrapper.getParent();
 52         FilterMap filterMaps[] = context.findFilterMaps();
 53 
 54         // If there are no filter mappings, we are done
 55         if ((filterMaps == null) || (filterMaps.length == 0))
 56             return (filterChain);
 57 
 58         // Acquire the information we will need to match filter mappings
 59         String servletName = wrapper.getName();
 60 
 61         // Add the relevant path-mapped filters to this filter chain
 62         for (int i = 0; i < filterMaps.length; i++) {
 63             if (!matchDispatcher(filterMaps[i] ,dispatcher)) {
 64                 continue;
 65             }
 66             if (!matchFiltersURL(filterMaps[i], requestPath))
 67                 continue;
 68             ApplicationFilterConfig filterConfig = (ApplicationFilterConfig)
 69                 context.findFilterConfig(filterMaps[i].getFilterName());
 70             if (filterConfig == null) {
 71                 // FIXME - log configuration problem
 72                 continue;
 73             }
 74             boolean isCometFilter = false;
 75             if (comet) {
 76                 try {
 77                     isCometFilter = filterConfig.getFilter() instanceof CometFilter;
 78                 } catch (Exception e) {
 79                     // Note: The try catch is there because getFilter has a lot of 
 80                     // declared exceptions. However, the filter is allocated much
 81                     // earlier
 82                     Throwable t = ExceptionUtils.unwrapInvocationTargetException(e);
 83                     ExceptionUtils.handleThrowable(t);
 84                 }
 85                 if (isCometFilter) {
 86                     filterChain.addFilter(filterConfig);
 87                 }
 88             } else {
 89                 filterChain.addFilter(filterConfig);
 90             }
 91         }
 92 
 93         // Add filters that match on servlet name second
 94         for (int i = 0; i < filterMaps.length; i++) {
 95             if (!matchDispatcher(filterMaps[i] ,dispatcher)) {
 96                 continue;
 97             }
 98             if (!matchFiltersServlet(filterMaps[i], servletName))
 99                 continue;
100             ApplicationFilterConfig filterConfig = (ApplicationFilterConfig)
101                 context.findFilterConfig(filterMaps[i].getFilterName());
102             if (filterConfig == null) {
103                 // FIXME - log configuration problem
104                 continue;
105             }
106             boolean isCometFilter = false;
107             if (comet) {
108                 try {
109                     isCometFilter = filterConfig.getFilter() instanceof CometFilter;
110                 } catch (Exception e) {
111                     // Note: The try catch is there because getFilter has a lot of 
112                     // declared exceptions. However, the filter is allocated much
113                     // earlier
114                 }
115                 if (isCometFilter) {
116                     filterChain.addFilter(filterConfig);
117                 }
118             } else {
119                 filterChain.addFilter(filterConfig);
120             }
121         }
122 
123         // Return the completed filter chain
124         return (filterChain);
125 
126     }

  可以將如上代碼分為兩段,51行之前為第一段,51行之後為第二段。   第一段的主要目的是創建ApplicationFilterChain對象以及一些參數設置。   第二段的主要目的是從上下文中獲取所有Filter信息,之後使用for循環遍歷並調用filterChain.addFilter(filterConfig);將filterConfig放入ApplicationFilterChain對象的ApplicationFilterConfig數組中。

  (5)那ApplicationFilterFactory類的createFilterChain()方法又是在什麽地方被調用的呢?

 是在StandardWrapperValue類的invoke()方法中被調用的。   技術分享 由於invoke()方法較長,所以將很多地方省略。
 public final void invoke(Request request, Response response)
        throws IOException, ServletException {
   ...省略中間代碼
     // Create the filter chain for this request
        ApplicationFilterFactory factory =
            ApplicationFilterFactory.getInstance();
        ApplicationFilterChain filterChain =
            factory.createFilterChain(request, wrapper, servlet);
  ...省略中間代碼
         filterChain.doFilter(request.getRequest(), response.getResponse());
  ...省略中間代碼
    }
  那正常的流程應該是這樣的:   在StandardWrapperValue類的invoke()方法中調用ApplicationFilterChai類的createFilterChain()方法 --> 在ApplicationFilterChai類的createFilterChain()方法中調用ApplicationFilterChain類的addFilter()方法 --> 在ApplicationFilterChain類的addFilter()方法中給ApplicationFilterConfig數組賦值。 技術分享 根據上面的代碼可以看出StandardWrapperValue類的invoke()方法在執行完createFilterChain()方法後,會繼續執行ApplicationFilterChain類的doFilter()方法,然後在doFilter()方法中會調用internalDoFilter()方法。   以下是internalDoFilter()方法的部分代碼
        // Call the next filter if there is one
        if (pos < n) {
       //拿到下一個Filter,將指針向下移動一位
            //pos它來標識當前ApplicationFilterChain(當前過濾器鏈)執行到哪個過濾器
            ApplicationFilterConfig filterConfig = filters[pos++];
            Filter filter = null;
            try {
          //獲取當前指向的Filter的實例
                filter = filterConfig.getFilter();
                support.fireInstanceEvent(InstanceEvent.BEFORE_FILTER_EVENT,
                                          filter, request, response);
                
                if (request.isAsyncSupported() && "false".equalsIgnoreCase(
                        filterConfig.getFilterDef().getAsyncSupported())) {
                    request.setAttribute(Globals.ASYNC_SUPPORTED_ATTR,
                            Boolean.FALSE);
                }
                if( Globals.IS_SECURITY_ENABLED ) {
                    final ServletRequest req = request;
                    final ServletResponse res = response;
                    Principal principal = 
                        ((HttpServletRequest) req).getUserPrincipal();

                    Object[] args = new Object[]{req, res, this};
                    SecurityUtil.doAsPrivilege
                        ("doFilter", filter, classType, args, principal);
                    
                } else {
            //調用Filter的doFilter()方法  
                    filter.doFilter(request, response, this);
                }
  這裏的filter.doFilter(request, response, this);就是調用我們前面創建的TestFilter中的doFilter()方法。而TestFilter中的doFilter()方法會繼續調用chain.doFilter(request, response);方法,而這個chain其實就是ApplicationFilterChain,所以調用過程又回到了上面調用dofilter和調用internalDoFilter方法,這樣執行直到裏面的過濾器全部執行。   如果定義兩個過濾器,則Debug結果如下: 技術分享

設計模式(13)--Chain of Responsibility(責任鏈模式)--行為型