Java Servlet Filter
做web開發的人對於Filter應該不會陌生,一直在很簡單的使用,但是一直沒有系統的總結一下,隨著年紀的慢慢長大,喜歡總結一些事情,下面說說我對Filter的理解,官方給出的Filter的定義是在請求一個資源或者從一個資源返回資訊的時候執行過濾操作的外掛。我們使用過濾起最多的場景估計就是在請求和返回時候的字符集轉換,或者許可權控制,比如一個使用者沒有登入不能請求某些資源。下面看一下Filter的集中型別:
- Authentication Filters
- Logging and Auditing Filters
- Image conversion Filters
- Data compression Filters
- Encryption Filters
- Tokenizing Filters
- Filters that trigger resource access events
- XSL/T filters
- Mime-type chain Filter
Filters是在web.xml中配置的外掛,Servlets和Filters相互沒有依賴,如果通過編輯web.xml來新增和刪除過濾器。
實現過濾器非常簡單,只需要實現javax.servlet.Filter介面,就可以實現一個過濾器,Filter介面定義的方法如下:
- void init(FilterConfig filterConfig))--在filter被載入到service中的時候被container呼叫,Servlet container例項化完filter以後立即呼叫Filter的init方法,init方法中的工作必須在執行過濾過濾任務之前正確的完成。
在以下情況下web container不能把filter載入到service中:
-
- 丟擲ServletException異常。
- 在container定義的時間內沒有返回。
- void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)--Filter中的doFilter方法在每次request/response時候會被container呼叫,能夠傳遞到doFilter中的request或者response可以傳遞到Filter環中的下一個環節。 此時的Filter在設計模式中被稱作責任鏈模式結構,這裡面抽象處理者的角色就是javax.servlet.Filter這個介面,註冊的所有Filter是具體的處理者,在doFilter方法中實現具體處理邏輯,在這裡面責任鏈是一條直線,構成這條直線的就是所有註冊的Filter。
- destroy--當filter從service中移除的時候,container呼叫destroy方法,通過呼叫這個方法,釋放Filter所佔有的系統資源。
如何在web.xml中配置Filter
1 <filter> 2 <display-name>EcodingFilter</display-name> 3 <filter-name>EcodingFilter</filter-name> 4 <filter-class>org.nb.filter.EnCodeFilter</filter-class> 5 <init-param> 6 <param-name>EncodeCoding</param-name> 7 <param-value>UTF-8</param-value> 8 </init-param> 9 </filter>
我們可以使用如下方法來給Filter匹配指定的servlet 資源或者url-pattern:
1 <filter-mapping> 2 <filter-name>EcodingFilter</filter-name> 3 <servlet-name>*</servlet-name> 4 <url-pattern>*</url-pattern> 5 </filter-mapping>
在這裡需要注意的是,在給servlet註冊filter環,container首先處理的是url-patterns,然後才處理servlet-names,所以如果要對filter的執行順序有要求,那麼在此需要注意。下面我們建立一個web工程,來實踐一下Filter:
web.xml內容:
1 <?xml version="1.0" encoding="UTF-8"?> 2 <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 3 xmlns="http://java.sun.com/xml/ns/javaee" 4 xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" 5 version="3.0"> 6 <display-name>FilterTest</display-name> 7 <welcome-file-list> 8 <welcome-file>index.html</welcome-file> 9 </welcome-file-list> 10 <filter> 11 <display-name>EcodingFilter</display-name> 12 <filter-name>EcodingFilter</filter-name> 13 <filter-class>org.nb.filter.EnCodeFilter</filter-class> 14 <init-param> 15 <param-name>EncodeCoding</param-name> 16 <param-value>UTF-8</param-value> 17 </init-param> 18 </filter> 19 <filter-mapping> 20 <filter-name>EcodingFilter</filter-name> 21 <servlet-name>hello</servlet-name> 22 <url-pattern>*</url-pattern> 23 </filter-mapping> 24 <servlet> 25 <servlet-name>hello</servlet-name> 26 <servlet-class></servlet-class> 27 </servlet> 28 <servlet-mapping> 29 <servlet-name>hello</servlet-name> 30 <url-pattern>/*</url-pattern> 31 </servlet-mapping> 32 </web-app>
HelloServlet.java內容:
1 package org.nb.action; 2 3 import java.io.IOException; 4 import java.io.PrintWriter; 5 6 import javax.servlet.ServletException; 7 import javax.servlet.annotation.WebServlet; 8 import javax.servlet.http.HttpServlet; 9 import javax.servlet.http.HttpServletRequest; 10 import javax.servlet.http.HttpServletResponse; 11 12 @WebServlet("/helloServlet") 13 public class HelloServlet extends HttpServlet { 14 private static final long serialVersionUID = 1L; 15 16 protected void doPost(HttpServletRequest request, 17 HttpServletResponse response) throws ServletException, IOException { 18 PrintWriter out = response.getWriter(); 19 out.println("<font color=red>Hello.</font>"); 20 } 21 }
EnCodeFilter.xm內容:
1 package org.nb.filter; 2 3 import java.io.IOException; 4 import java.util.Enumeration; 5 import java.util.HashMap; 6 import java.util.Map; 7 8 import javax.servlet.Filter; 9 import javax.servlet.FilterChain; 10 import javax.servlet.FilterConfig; 11 import javax.servlet.ServletException; 12 import javax.servlet.ServletRequest; 13 import javax.servlet.ServletResponse; 14 15 public class EnCodeFilter implements Filter { 16 17 Map<String, String> params = new HashMap<String, String>(); 18 19 @Override 20 public void destroy() { 21 System.out.println("EncodeFilter destroy"); 22 } 23 24 @Override 25 public void doFilter(ServletRequest request, ServletResponse response, 26 FilterChain chain) throws IOException, ServletException { 27 String encodeCoding = params.get("EncodeCoding"); 28 request.setCharacterEncoding(encodeCoding); 29 response.setCharacterEncoding(encodeCoding); 30 chain.doFilter(request, response); 31 System.out.println("EncodeFilter doFilter"); 32 } 33 34 @Override 35 public void init(FilterConfig cfg) throws ServletException { 36 Enumeration<String> names = cfg.getInitParameterNames(); 37 while (names.hasMoreElements()) { 38 String name = names.nextElement(); 39 params.put(name, cfg.getInitParameter(name)); 40 } 41 System.out.println("EncodeFilter init"); 42 } 43 44 }
在tomcat啟動的時候Console輸出的內容:
三月 24, 2014 5:56:12 下午 org.apache.catalina.core.AprLifecycleListener init 資訊: The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: E:\Program Files\Java\jre7\bin;C:\Windows\Sun\Java\bin;C:\Windows\system32;C:\Windows;C:\Program Files (x86)\M1 Licensing;C:\Program Files\Broadcom\Broadcom 802.11 Network Adapter\Driver;C:\Program Files (x86)\NVIDIA Corporation\PhysX\Common;C:\PROGRAM FILES (X86)\INTEL\ICLS CLIENT\;C:\PROGRAM FILES\INTEL\ICLS CLIENT\;C:\Windows\SYSTEM32;C:\Windows;C:\Windows\SYSTEM32\WBEM;C:\Windows\SYSTEM32\WINDOWSPOWERSHELL\V1.0\;C:\PROGRAM FILES (X86)\INTEL\OPENCL SDK\2.0\BIN\X86;C:\PROGRAM FILES (X86)\INTEL\OPENCL SDK\2.0\BIN\X64;C:\PROGRAM FILES\INTEL\INTEL(R) MANAGEMENT ENGINE COMPONENTS\DAL;C:\PROGRAM FILES\INTEL\INTEL(R) MANAGEMENT ENGINE COMPONENTS\IPT;C:\PROGRAM FILES (X86)\INTEL\INTEL(R) MANAGEMENT ENGINE COMPONENTS\DAL;C:\PROGRAM FILES (X86)\INTEL\INTEL(R) MANAGEMENT ENGINE COMPONENTS\IPT;C:\PROGRAM FILES (X86)\LENOVO\ACCESS CONNECTIONS\;C:\Program Files\WIDCOMM\Bluetooth Software\;C:\Program Files\WIDCOMM\Bluetooth Software\syswow64;C:\Program Files (x86)\Intel\OpenCL SDK\3.0\bin\x86;C:\Program Files (x86)\Intel\OpenCL SDK\3.0\bin\x64;E:\Ruby200\bin;E:\Program Files\TortoiseSVN\bin;E:\Program Files\MySQL\MySQL Utilities 1.3.4\;C:\Program Files\Microsoft\Web Platform Installer\;C:\Program Files (x86)\Microsoft ASP.NET\ASP.NET Web Pages\v1.0\;C:\Program Files (x86)\Windows Kits\8.0\Windows Performance Toolkit\;C:\Program Files\Microsoft SQL Server\110\Tools\Binn\;E:\Program Files\Java\jdk1.7.0_40\bin;C:\Program Files (x86)\Microsoft SQL Server\100\Tools\Binn\;C:\Program Files\Microsoft SQL Server\100\Tools\Binn\;C:\Program Files\Microsoft SQL Server\100\DTS\Binn\;F:\instantclient;.;;.;;. 三月 24, 2014 5:56:12 下午 org.apache.tomcat.util.digester.SetPropertiesRule begin 警告: [SetPropertiesRule]{Server/Service/Engine/Host/Context} Setting property 'source' to 'org.eclipse.jst.jee.server:FilterTest' did not find a matching property. 三月 24, 2014 5:56:13 下午 org.apache.coyote.AbstractProtocolHandler init 資訊: Initializing ProtocolHandler ["http-bio-8080"] 三月 24, 2014 5:56:13 下午 org.apache.coyote.AbstractProtocolHandler init 資訊: Initializing ProtocolHandler ["ajp-bio-8009"] 三月 24, 2014 5:56:13 下午 org.apache.catalina.startup.Catalina load 資訊: Initialization processed in 1031 ms 三月 24, 2014 5:56:13 下午 org.apache.catalina.core.StandardService startInternal 資訊: Starting service Catalina 三月 24, 2014 5:56:13 下午 org.apache.catalina.core.StandardEngine startInternal 資訊: Starting Servlet Engine: Apache Tomcat/7.0.8 EncodeFilter init 三月 24, 2014 5:56:13 下午 org.apache.catalina.startup.HostConfig deployDirectory 資訊: Deploying web application directory docs 三月 24, 2014 5:56:13 下午 org.apache.catalina.startup.HostConfig deployDirectory 資訊: Deploying web application directory examples 三月 24, 2014 5:56:13 下午 org.apache.catalina.core.ApplicationContext log 資訊: ContextListener: contextInitialized() 三月 24, 2014 5:56:13 下午 org.apache.catalina.core.ApplicationContext log 資訊: SessionListener: contextInitialized() 三月 24, 2014 5:56:13 下午 org.apache.catalina.startup.HostConfig deployDirectory 資訊: Deploying web application directory host-manager 三月 24, 2014 5:56:13 下午 org.apache.catalina.startup.HostConfig deployDirectory 資訊: Deploying web application directory manager 三月 24, 2014 5:56:14 下午 org.apache.catalina.startup.HostConfig deployDirectory 資訊: Deploying web application directory ROOT 三月 24, 2014 5:56:14 下午 org.apache.coyote.AbstractProtocolHandler start 資訊: Starting ProtocolHandler ["http-bio-8080"] 三月 24, 2014 5:56:14 下午 org.apache.coyote.AbstractProtocolHandler start 資訊: Starting ProtocolHandler ["ajp-bio-8009"] 三月 24, 2014 5:56:14 下午 org.apache.catalina.startup.Catalina start 資訊: Server startup in 978 ms
其中有filter,init方法的輸出,下面建立一個index.html檔案,內容如下:
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="UTF-8"> 5 <title>Insert title here</title> 6 </head> 7 <body> 8 <form action="http://localhost:8080/FilterTest/helloServlet" method="post"> 9 <input type="submit" value="Login"> 10 </form> 11 </body> 12 </html>
點選index.html頁面的按鈕,
此時Console輸出內容:
1 EncodeFilter doFilter
每次請求都會有這樣一條輸出。
關閉tomcat的時候,注意觀察Console輸出的內容:
三月 24, 2014 6:08:33 下午 org.apache.catalina.core.StandardServer await
資訊: A valid shutdown command was received via the shutdown port. Stopping the Server instance.
三月 24, 2014 6:08:33 下午 org.apache.coyote.AbstractProtocolHandler pause
資訊: Pausing ProtocolHandler ["http-bio-8080"]
三月 24, 2014 6:08:34 下午 org.apache.coyote.AbstractProtocolHandler pause
資訊: Pausing ProtocolHandler ["ajp-bio-8009"]
三月 24, 2014 6:08:35 下午 org.apache.catalina.core.StandardService stopInternal
資訊: Stopping service Catalina
EncodeFilter destroy
三月 24, 2014 6:08:36 下午 org.apache.catalina.core.ApplicationContext log
資訊: SessionListener: contextDestroyed()
三月 24, 2014 6:08:36 下午 org.apache.catalina.core.ApplicationContext log
資訊: ContextListener: contextDestroyed()
三月 24, 2014 6:08:37 下午 org.apache.coyote.AbstractProtocolHandler stop
資訊: Stopping ProtocolHandler ["http-bio-8080"]
三月 24, 2014 6:08:37 下午 org.apache.coyote.AbstractProtocolHandler stop
資訊: Stopping ProtocolHandler ["ajp-bio-8009"]
此時Fileter的Destroy方法被呼叫。Filter的生命週期結束。這篇文章中包含一些資訊,如Server,Service,Container等,可能有些人跟我一樣開始的時候對此很不瞭解,如果這樣大家可以查一下Tomcat等web容器的工作原理,如果有什麼地方我說的不清楚,或者有錯誤,那麼請提醒我,謝謝。