servlet中Filter介面介紹
過濾器是指攔截請求,並對傳給被請求資源的ServletRequest 或 ServletResponse 進行處理的一個物件。過濾器可以用於登入、加密和解密、會話檢查等等。過濾器可以配置為攔截一個或多個資源。如果同一個資源或同一組資源中應用了多個過濾器,則呼叫順序有顯示顯得比較重要,這時候就需要部署描述符(web.xml)來控制其先後順序。
filter過濾器中使用的介面包括Filter、FilterConfig和FilterChain。每個介面中包含若干方法,接下來我們按照filter的生命週期來介紹介面及中間對應的方法。
過濾器類必須實現javax.servlet.Filter介面。這個介面為每個過濾器暴露3個生命週期方法,init、doFilter 和 destory。
package javax.servlet; import java.io.IOException; /** * A filter is an object that performs filtering tasks on either the request to * a resource (a servlet or static content), or on the response from a resource, * or both. <br> * @since Servlet 2.3 */ public interface Filter { /** * Called by the web container to indicate to a filter that it is being * placed into service. The servlet container calls the init method exactly * once after instantiating the filter. The init method must complete * successfully before the filter is asked to do any filtering work. <br> * <br> * The web container cannot place the filter into service if the init method * either<br> * 1.Throws a ServletException <br> * 2.Does not return within a time period defined by the web container */ public void init(FilterConfig filterConfig) throws ServletException; /** * The <code>doFilter</code> method of the Filter is called by the container * each time a request/response pair is passed through the chain due to a * client request for a resource at the end of the chain. The FilterChain * passed in to this method allows the Filter to pass on the request and * response to the next entity in the chain. * <p> * A typical implementation of this method would follow the following * pattern:- <br> * 1. Examine the request<br> * 2. Optionally wrap the request object with a custom implementation to * filter content or headers for input filtering <br> * 3. Optionally wrap the response object with a custom implementation to * filter content or headers for output filtering <br> * 4. a) <strong>Either</strong> invoke the next entity in the chain using * the FilterChain object (<code>chain.doFilter()</code>), <br> * 4. b) <strong>or</strong> not pass on the request/response pair to the * next entity in the filter chain to block the request processing<br> * 5. Directly set headers on the response after invocation of the next * entity in the filter chain. **/ public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException; /** * Called by the web container to indicate to a filter that it is being * taken out of service. This method is only called once all threads within * the filter's doFilter method have exited or after a timeout period has * passed. After the web container calls this method, it will not call the * doFilter method again on this instance of the filter. <br> * <br> * * This method gives the filter an opportunity to clean up any resources * that are being held (for example, memory, file handles, threads) and make * sure that any persistent state is synchronized with the filter's current * state in memory. */ public void destroy(); }
當過濾器啟動服務的時候,比如應用程式啟動時,servlet容器就會呼叫init方法。換句話說,不用等到呼叫與被過濾器相關的資源之後,才呼叫init方法。這個方法只調用一次,並且應該包含該過濾器的初始化程式碼。
init方法的簽名如下:
void init(FilterConfig filterConfig)
注意:servlet容器給init方法傳遞了一個FilterConfig。
FilterConfig 介面
package javax.servlet; import java.util.Enumeration; /** * A filter configuration object used by a servlet container to pass information * to a filter during initialization. */ public interface FilterConfig { /** * Returns the filter-name of this filter as defined in the deployment * descriptor. */ public String getFilterName(); /** * Returns a reference to the {@link ServletContext} in which the caller is * executing. */ public ServletContext getServletContext(); /** * Returns a <code>String</code> containing the value of the named * initialization parameter, or <code>null</code> if the parameter does not * exist. */ public String getInitParameter(String name); /** * Returns the names of the filter's initialization parameters as an * <code>Enumeration</code> of <code>String</code> objects, or an empty * <code>Enumeration</code> if the filter has no initialization parameters. */ public Enumeration<String> getInitParameterNames(); }
每次呼叫與過濾器相關的資源時,servlet容器都會呼叫Filter例項的doFilter方法。該方法會收到一個ServletRequest、ServletResponse和FilterChain。
doFilter方法的簽名如下:
public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain arg2)
doFilter的實現可以訪問ServletRequest 和 ServletResponse。因此,可以在ServletRequest中新增屬性,或者在ServletResponse中新增一個標頭,甚至可以對ServletRequest 或 ServletResponse進行修復,改變它們的行為。
doFilter方法實現中最後一行程式碼應該是呼叫FilterChain中的doFilter方法,
FilterChain.doFilter方法簽名為
public void doFilter(ServletRequest request, ServletResponse response)
一個資源可以與多個過濾器關聯,FilterChain.doFilter( ) 通常會引發呼叫鏈中的下一個過濾器被呼叫。在鏈中的最後一個過濾器中呼叫FilterChain.doFilter( )會引發資源本身被呼叫。如果你沒有在 Filter.doFilter( )方法實現程式碼的最後呼叫FilterChain.doFilter( )方法,那麼程式的處理將會在這裡停止,並且不會呼叫請求。
注意,doFilter方法是FilterChain介面中唯一的方法,它與Filter中的doFilter方法不同。在FilterChain中,doFilter只有兩個引數,而不是三個。
Filter中最後一個生命週期方法是destory,其方法簽名為
void destroy()
這個方法在過濾器即將終止服務之前,由Servlet呼叫,一般發生在應用程式停止的時候。
Demo
package com.filter;
import java.io.IOException;
import java.util.Enumeration;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
public class HttpFilter implements Filter {
@Override
public void destroy() {
System.out.println("過濾器生命終止");
}
@Override
public void doFilter(ServletRequest arg0, ServletResponse arg1,
FilterChain arg2) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest)arg0;
// 列印請求的URL
System.out.println("filter1 " + req.getRequestURL());
arg2.doFilter(arg0, arg1);
}
@Override
public void init(FilterConfig arg0) throws ServletException {
System.out.println("過濾器生命開始");
String filterName = arg0.getFilterName();
System.out.println("過濾器名為 " + filterName);
// 遍歷過濾器中的引數和對應值
Enumeration<String> initParas = arg0.getInitParameterNames();
String paraName;
String paraValue;
while (initParas.hasMoreElements()) {
paraName = initParas.nextElement();
paraValue = arg0.getInitParameter(paraName);
System.out.println(paraName + " = " + paraValue);
}
}
}
部署描述符web.xml中配置為
<filter>
<filter-name>httpFilter</filter-name>
<filter-class>com.filter.HttpFilter</filter-class>
<init-param>
<param-name>creater</param-name>
<param-value>zhangqi</param-value>
</init-param>
<init-param>
<param-name>createrDate</param-name>
<param-value>2017-05-20</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>httpFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
伺服器啟動時,可以在控制檯中看到
過濾器生命開始
過濾器名為 httpFilter
creater = zhangqi
createrDate = 2017-05-20
說明,過濾器是在伺服器啟動時載入,且呼叫了init方法。
然後我們訪問下初始化頁面,控制檯可以看到
filter1 http://localhost:8080/servletDemo/
說明,這個請求被過濾器攔截,過濾器打印出了請求的URL。
最後,我們停止tomcat伺服器,控制檯可以看到
過濾器生命終止
說明,伺服器停止前,服務終止時,會呼叫destory方法,銷燬過濾器物件。