責任鏈模式
責任鏈模式是一種對象的行為模式。在責任鏈模式里,很多對象由每一個對象對其下家的引用而連接起來形成一條鏈。請求在這個鏈上傳遞,直到鏈上的某一個對象決定處理此請求。發出這個請求的客戶端並不知道鏈上的哪一個對象最終處理這個請求,這使得系統可以在不影響客戶端的情況下動態地重新組織和分配責任。Tomcat中的Filter就是使用了責任鏈模式,創建一個Filter除了要在web.xml文件中做相應配置外,還需要實現javax.servlet.Filter接口。
為了方便理解,責任鏈模式直接用馬士兵老師中的一個例子來講解,做下筆記也方便自己以后的復習查詢:
我們有一個字符串String msg = ":):,<script>,敏感,被就業,網絡授課";我們希望應用以下三個規則對字符串進行過濾和諧處理:
(1)將字符串中出現的"<>"符號替換成"[]"
(2)處理字符串中的敏感信息,將被就業和諧成就業
(3)將字符串中出現的":):"轉換成"^V^";
字符串會依次運用這三條規則,對字符串進行處理,每個規則都有自己需要完成的責任和任務。
第一步:定義封裝請求的類Request和封裝處理結果響應的類Response
//封裝請求的類Request public class Request { String requestStr; public String getRequest() { return requestStr; } public void setRequest(String request) { this.requestStr = request; } }
//封裝響應信息的類Response public class Response { String responseStr; public String getResponse() { return responseStr; } public void setResponse(String response) { this.responseStr = response; } }
第二步:定義具有過濾功能的接口Filter,具體的過濾規則需要實現該接口
/* * 定義接口Filter,具體的過濾規則需要實現這個接口,最后一個參數添加的意義是我們在Main函數中: * fc.doFilter(request, response,fc);執行這一步的時候可以按照規則鏈條一次使用三個過濾規則對字符串進行處理 * 因為 * */ public interface Filter { void doFilter(Request request,Response response,FilterChain chain); }
第三步:定義具體的過濾處理規則
規則一
package com.bjsxt.dp.filter; //處理字符串中的HTML標記 public class HTMLFilter implements Filter { public void doFilter(Request request, Response response,FilterChain chain) { //將字符串中出現的"<>"符號替換成"[]" request.requestStr=request.requestStr .replace('<', '[').replace('>', ']')+ //后面添加的是便於我們觀察代碼執行步驟的字符串 "----HTMLFilter()"; chain.doFilter(request, response,chain); response.responseStr+="---HTMLFilter()"; } }
規則二
package com.bjsxt.dp.filter; //定義的過濾敏感字眼的過濾規則 public class SensitiveFilter implements Filter{ public void doFilter(Request request, Response response,FilterChain chain) { //處理字符串中的敏感信息,將被就業和諧成就業 request.requestStr=request.requestStr .replace("被就業", "就業").replace("敏感", "")+ //后面添加的是便於我們觀察代碼執行步驟的字符串 " ---sensitiveFilter()"; chain.doFilter(request, response,chain); response.responseStr+="---sensitiveFilter()"; } }
規則三:
package com.bjsxt.dp.filter; //定義FaceFilter public class FaceFilter implements Filter { public void doFilter(Request request, Response response, FilterChain chain) { //將字符串中出現的":):"轉換成"^V^"; request.requestStr = request.requestStr.replace(":):", "^V^") //后面添加的是便於我們觀察代碼執行步驟的字符串 + "----FaceFilter()"; chain.doFilter(request, response, chain); response.responseStr += "---FaceFilter()"; } }
第四步:定義責任鏈FilterChain
package com.bjsxt.dp.filter; import java.util.ArrayList; import java.util.List; //過濾鏈條 public class FilterChain implements Filter{ //用List集合來存儲過濾規則 List<Filter> filters = new ArrayList<Filter>(); //用於標記規則的引用順序 int index=0; //往規則鏈條中添加規則 public FilterChain addFilter(Filter f) { filters.add(f); //代碼的設計技巧:Chain鏈添加過濾規則結束后返回添加后的Chain,方便我們下面doFilter函數的操作 return this; } public void doFilter(Request request,Response response,FilterChain chain){ //index初始化為0,filters.size()為3,不會執行return操作 if(index==filters.size()){ return; } //每添加一個過濾規則,index自增1 Filter f=filters.get(index); index++; //根據索引值獲取對應的規律規則對字符串進行處理 f.doFilter(request, response, chain); } }
第五步:測試一下我們的代碼
package com.bjsxt.dp.filter; import java.util.ArrayList; import java.util.List; //過濾鏈條 public class FilterChain implements Filter{ //用List集合來存儲過濾規則 List<Filter> filters = new ArrayList<Filter>(); //用於標記規則的引用順序 int index=0; //往規則鏈條中添加規則 public FilterChain addFilter(Filter f) { filters.add(f); //代碼的設計技巧:Chain鏈添加過濾規則結束后返回添加后的Chain,方便我們下面doFilter函數的操作 return this; } public void doFilter(Request request,Response response,FilterChain chain){ //index初始化為0,filters.size()為3,不會執行return操作 if(index==filters.size()){ return; } //每添加一個過濾規則,index自增1 Filter f=filters.get(index); index++; //根據索引值獲取對應的規律規則對字符串進行處理 f.doFilter(request, response, chain); } }
運行結果:
^V^,[script],,就業,網絡授課----HTMLFilter() ---sensitiveFilter()----FaceFilter()
response:---FaceFilter()---sensitiveFilter()---HTMLFilter()
代碼可以使用Eclipse中設置斷點,debug單步調試去驗證,我們下面帶着大家一塊執行一下上面的代碼。
(1)主函數中執行到fc.doFilter(request, response,fc);我們在此處設置斷點(Eclipse設置斷點的方式:在這行左面,雙擊那個豎邊框的對應位置即可設置斷點),現在的執行情況是下面這樣,代碼上面可以看到執行過程,現在停留在Main.main函數中。
(2)我們點擊左上角的Step Into(F5)進入到doFilter(request,response,fc)中
現在執行位置在FilterChain.doFilter,依次執行代碼,因為此時的index還是0,因此不可能執行return操作,跳過if代碼塊,調用索引值為0的規則HTMLFilter,index自增1,執行f.doFilter(request, response, chain);現在進入到了HTMLFilter類中的doFilter方法中
依次執行代碼,對字符串請求進行處理,執行到chain.doFilter(request, response,chain)這一句,會再次進入FilterChain中的doFilter方法內
此時的index為1,仍然跳過if代碼塊執行下面的步驟,和上面一樣,用索引值為1的規則進行處理,index自增1現在變成2了。執行f.doFilter(request, response, chain);會進入到SensitiveFilter中的doFilter方法執行
第三個規則的應用和前兩個一致,直接給出執行到FaceFilter類中的doFilter方法的結果截圖
現在執行到if判斷,index的值為3,滿足判斷條件返回,上圖中最上面的函數退棧,回到FaceFilter.doFilter函數中執行response.responseStr += "---FaceFilter()";這就是我們運行結果中response中的第一部分。函數會依次退棧,response不斷添加已經做過處理的規則的信息response.responseStr+="---sensitiveFilter()";response.responseStr+="---HTMLFilter()";最終回到Main.main函中打印reponse信息
運行過程用下圖表示: