1. 前言
? ? ? ?Filter—Filter 技術是servlet2.3 新增加的功能。完成的流程:對用戶請求進行預處理,接著將請求交給Servlet進行處理并生成響應,最后Filter再對服務器響應進行后處理。
? ? ? ?Filter體現了一種職責璉模式。那么他是如何體現的呢?
spring職責鏈 動態編排、2. 職責鏈模式
? ? ? 在具體的解釋這個之前先看看職責鏈模式的定義:使多個對象都有機會處理請求 ,從而避免請求的發送者和接受者之間的耦合關系。將這個對象連成一個鏈,并沿著這條鏈傳遞請求,直到有一個對象處理它為止。
? ? ? ?對于Filter而言就是,請求傳給具體的web資源(比如jsp/servlet)之前要經過Filter的預處理,在web資源處理完成返回給客戶端之前也要被Filter處理一遍。就好比下面的這種圖
??
設計模式體現了單一職責原則、?
? ? ? ?當創建了多個Filter之后,客戶端傳來一個Request請求,它就面對著這一個Filter鏈,職責璉模式就體現在這里。這個請求會在這個 Filter鏈上一個一個被傳遞下去對它進行預處理,處理完成之后就傳給下一個Filter直到最后一個,然后才交給web進行相應的訪問和處理。它的 uml圖(并不是完成的結構圖,只是體現職責璉模式的結構圖)如下:
? ? ?
? ? ? ?一個Filter接口定義了三個方法:init()(初始化方法);destroy()(銷毀方法);doFilter()(核心的職責方法);兩個具體類實現了Filter接口:ConcreteFilter1和ConcreteFilter2;
職責鏈模式和裝飾者模式?? ? ? 一個FilterChain接口定義了一個方法:doFilter();一個具體的實現類ConcreteFilterChain;
? ? ? 其中FilterChain主要的作用是完成找到下一個Filter。
3. 具體的實現
?
什么是職責鏈模式、? ? ?下面是對于上面結構圖的一個簡單實現,幫助我們理解一下Filter體現的職責璉模式。
? ?ConcreteFilter1類
- package?com.test.filter;??
- ??
- import?java.io.IOException;??
- ??
- import?javax.servlet.Filter;??
- import?javax.servlet.FilterChain;??
- import?javax.servlet.FilterConfig;??
- import?javax.servlet.ServletException;??
- import?javax.servlet.ServletRequest;??
- import?javax.servlet.ServletResponse;??
- ??
- /**?
- ?*?ConcreteFilter1類?
- ?*?@author?pf?
- ?*?
- ?*/??
- public?class?ConcreteFilter1?implements?Filter?{??
- ??????
- //??private?String?encoding;??
- ??????
- ????@Override??
- ????public?void?destroy()?{??
- ????????System.out.println("ConcreteFilter1()的destroy()執行");??
- ????}??
- ??
- ????@Override??
- ????public?void?doFilter(ServletRequest?request,?ServletResponse?response,??
- ????????????FilterChain?chain)?throws?IOException,?ServletException?{??
- ????????System.out.println("----ConcreteFilter1()的chain.doFilter()調用之前:對用戶請求(request)進行預處理");??
- ????????//繼續執行??
- ????????//后面有filter繼續調用,沒有的話就進入到了jsp,一直調用最后??
- ????????chain.doFilter(request,?response);??
- ????????System.out.println("ConcreteFilter1()的chain.doFilter()調用之后:對服務器響應(response)進行后處理");??
- ????}??
- ??
- ????@Override??
- ????public?void?init(FilterConfig?filterConfig)?throws?ServletException?{??
- //??????System.out.println("init開始");??
- //??????this.encoding?=?filterConfig.getInitParameter("encoding");??
- //??????System.out.println("init得到encoding:"?+?encoding);??
- ????????System.out.println("ConcreteFilter1()的init()方法調用");??
- ??????????
- ????}??
- ??
- }??
ConcreteFilter2類
- package?com.test.filter;??
- ??
- import?java.io.IOException;??
- ??
- import?javax.servlet.Filter;??
- import?javax.servlet.FilterChain;??
- import?javax.servlet.FilterConfig;??
- import?javax.servlet.ServletException;??
- import?javax.servlet.ServletRequest;??
- import?javax.servlet.ServletResponse;??
- ??
- /**?
- ?*?采用Filter統一處理字符集?
- ?*?@author?pf?
- ?*?
- ?*/??
- public?class?ConcreteFilter2?implements?Filter?{??
- ??????
- //??private?String?encoding;??
- ????@Override??
- ????public?void?destroy()?{??
- ????????System.out.println("ConcreteFilter2()的destroy()執行");??
- ????}??
- ??
- ????@Override??
- ????public?void?doFilter(ServletRequest?request,?ServletResponse?response,??
- ????????????FilterChain?chain)?throws?IOException,?ServletException?{??
- ????????System.out.println("ConcreteFilter2()的chain.doFilter()調用之前");??
- //??????request.setCharacterEncoding(encoding);??
- ????????//后面有filter繼續調用,沒有的話就進入到了jsp,一直調用最后??
- ????????chain.doFilter(request,?response);??
- ????????System.out.println("ConcreteFilter2()的chain.doFilter()調用完成");??
- ????}??
- ??
- ????@Override??
- ????public?void?init(FilterConfig?filterConfig)?throws?ServletException?{??
- //??????System.out.println("init開始");??
- //??????this.encoding?=?filterConfig.getInitParameter("encoding");??
- //??????System.out.println("init得到encoding:"?+?encoding);??
- ????????System.out.println("ConcreteFilter2()的init()方法調用");??
- ????}??
- ??
- }??
單一職責?
web.xml
- <?xml?version="1.0"?encoding="UTF-8"?>??
- <web-app?version="2.4"???
- ????xmlns="http://java.sun.com/xml/ns/j2ee"???
- ????xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"???
- ????xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee???
- ????http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">??
- ??????
- ????<filter>??
- ????????<filter-name>ConcreteFilter1</filter-name>??
- ????????<filter-class>com.test.filter.ConcreteFilter1</filter-class>??
- ????</filter>??
- ????<filter-mapping>??
- ????????<filter-name>ConcreteFilter1</filter-name>??
- ????????<url-pattern>*.jsp</url-pattern>??
- ????</filter-mapping>??
- ????????<filter>??
- ????????<filter-name>ConcreteFilter2</filter-name>??
- ????????<filter-class>com.test.filter.ConcreteFilter2</filter-class>??
- ????</filter>??
- ????<filter-mapping>??
- ????????<filter-name>ConcreteFilter2</filter-name>??
- ????????<url-pattern>*.jsp</url-pattern>??
- ????</filter-mapping>??
- ??????
- </web-app>??
完成之后啟動服務器,我這里是tomcat,會顯示如下信息:
說明在啟動服務器的時候就會創建我們的Filter對象
職責鏈性能、隨便訪問一個頁面再次查看console
?? ? ? 關閉服務器:說明在關閉服務器的時候銷毀創建的Filter對象
? ? ?
什么責任鏈、? ? ? ?從上面的執行結果再來看一下Filter。我們設置了兩個Filter,分別是ConcreteFilter1和ConcreteFilter2.按照 我們在web.xml中配置的順序來執行,先執行了ConcreteFilter1,在執行ConcreteFilter2.
? ? ? 但是注意觀察,他們在真正調用chain的doFilter方法之后的調用順序正好相反了。所以我們從這個結果可以看到Filter的執行順序是遵循”后 進先出”的原則。現將傳來的url按照配置中的順序進行預處理,但是確實先按照相反的filter順序執行處理好的請求。
下面是講他的調用過程畫了一個時序圖:
基于價值鏈。3. 總結:
? ? ? ?通過上面代碼執行的結果來看,Filter很好的實現了職責鏈模式,對于任何一個請求來講都有一條Filter鏈可以處理它,具體是哪一個處理了我們其實并不知道但是在到達servlet之前就是已經給我們處理好了,這樣子就很好的做到了對象之間的解耦和。
?
原文:Filter體現職責鏈模式
?