Filter简介
从功能角度来说,Filter能做什么?
从API角度来说,如何实现Filter?
从原理角度来说,Filter是如何实现拦截的?
Filter生命周期和Filter链
Filter生命周期的三个方法:init、doFilter和destory
Filter链及其调用顺序
Filter高级开发
HttpServletRequestWrapper
HttpServletResponseWrapper
动态代理
Filter映射
Filter案例
1、Filter简介
1.1、从功能角度来说,Filter能做什么?
Filter也称之为过滤器,它是Servlet技术中最激动人心的技术。WEB开发人员通过Filter技术,对web服务器管理的所有web资源(例如Jsp, Servlet, 静态图片文件或静态 html 文件等)进行拦截,从而实现一些特殊的功能。例如实现URL级别的权限访问控制、过滤敏感词汇、压缩响应信息等一些高级功能。
1.2、从API角度来说,如何实现Filter?
Servlet API中提供了一个Filter接口,开发web应用时,如果编写的Java类实现了这个接口,则把这个java类称之为过滤器Filter。通过Filter技术,开发人员可以实现用户在访问某个目标资源之前,对访问的请求和响应进行拦截。
Filter开发分为二个步骤
1、编写java类实现javax.servlet.Filter接口,并实现其doFilter方法。
2、在 web.xml 文件中使用和元素对编写的filter类进行注册,并设置它所能拦截的资源。
HelloFilter.java
package com.rk.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; public class HelloFilter implements Filter { public HelloFilter() { System.out.println("HelloFilter构造函数!"); } @Override public void init(FilterConfig filterConfig) throws ServletException { System.out.println("HelloFilter.init()方法"); } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { System.out.println("HelloFilter.doFilter()前"); chain.doFilter(request, response); System.out.println("HelloFilter.doFilter()后"); } @Override public void destroy() { System.out.println("HelloFilter.destroy()"); } }
web.xml中的Filter映射配置
HelloFilter com.rk.filter.HelloFilter HelloFilter /*
1.3、从原理角度来说,Filter是如何实现拦截的?
Filter接口中有一个doFilter方法。WEB服务器每次在调用web资源的service方法之前,都会先调用一下filter的doFilter方法,因此,在该方法内编写代码可达到如下目的:
1)调用目标资源之前,让一段代码执行
2)是否调用目标资源(即是否让用户访问web资源)
web服务器在调用doFilter方法时,会传递一个filterChain对象进来。filterChain对象是filter接口中最重要的一个对象,它也提供了一个doFilter方法,开发人员可以根据需求决定是否调用此方法。如果调用该方法,则web服务器就会调用web资源的service方法,即web资源就会被访问,否则web资源不会被访问。
3)调用目标资源之后,让一段代码执行
Filter拦截的示意图:
2、Filter生命周期和Filter链
Filter生命周期,主要是在一个Filter内部,从Filter创建到Filter销毁的过程中,其内部方法的调用顺序。
Filter链,是当存在多个Filter时,形成的一种Filter对象顺序调用的“链/Chain”。
Filter生命周期解释的是一个Filter内部的执行顺序问题,而Filter链是多个Filter之间的调用顺序问题。
2.1、Filter生命周期的三个方法:init、doFilter和destory
javax.servlet.Filter接口的源码:
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. *
* Filters perform filtering in thedoFilter
method. Every Filter has access to ** a FilterConfig object from which it can obtain its initialization parameters, a ** reference to the ServletContext which it can use, for example, to load resources ** needed for filtering tasks. **** Filters are configured in the deployment descriptor of a web application **
** Examples that have been identified for this design are
** 1) Authentication Filters
** 2) Logging and Auditing Filters
** 3) Image conversion Filters
** 4) Data compression Filters
** 5) Encryption Filters
** 6) Tokenizing Filters
** 7) Filters that trigger resource access events
** 8) XSL/T filters
** 9) Mime-type chain Filter
* @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.
* The web container cannot place the filter into service if the init method either
* 1.Throws a ServletException
* 2.Does not return within a time period defined by the web container */ public void init(FilterConfig filterConfig) throws ServletException; /** * ThedoFilter
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.* A typical implementation of this method would follow the following pattern:-
* 1. Examine the request
* 2. Optionally wrap the request object with a custom implementation to * filter content or headers for input filtering
* 3. Optionally wrap the response object with a custom implementation to * filter content or headers for output filtering
* 4. a) Either invoke the next entity in the chain using the FilterChain object (chain.doFilter()
),
** 4. b) or not pass on the request/response pair to the next entity in the filter chain to block the request processing
** 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.
* * 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(); }
2.1.1、init(FilterConfig filterConfig)
和我们编写的Servlet程序一样,Filter的创建和销毁由WEB服务器负责。 web 应用程序启动时,web 服务器将创建Filter 的实例对象,并调用其init方法,完成对象的初始化功能,从而为后续的用户请求作好拦截的准备工作(注:filter对象只会创建一次,init方法也只会执行一次。 )
开发人员通过init方法的参数,可获得代表当前filter配置信息的FilterConfig对象。
javax.servlet.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 aString
containing the value of the * named initialization parameter, ornull
if * the parameter does not exist. */ public String getInitParameter(String name); /** * Returns the names of the filter's initialization parameters * as anEnumeration
ofString
objects, * or an emptyEnumeration
if the filter has * no initialization parameters. */ public Enumeration getInitParameterNames(); }
用户在配置filter时,可以使用为filter配置一些初始化参数;当web容器实例化Filter对象,调用其init方法时,会把封装了filter初始化参数的filterConfig对象传递进来。因此开发人员在编写filter时,通过filterConfig对象的方法:
(1)String getFilterName():得到filter的名称。
(2)String getInitParameter(String name): 返回在部署描述中指定名称的初始化参数的值。如果不存在返回null.
(3)Enumeration getInitParameterNames():返回过滤器的所有初始化参数的名字的枚举集合。
(4)public ServletContext getServletContext():返回Servlet上下文对象的引用。
2.1.2、doFilter ( ServletRequest request, ServletResponse response, FilterChain chain )
WEB服务器每次在调用web资源的service方法之前,都会先调用一下Filter的doFilter方法。
javax.servlet.FilterChain接口的源码:
package javax.servlet; import java.io.IOException; /** * A FilterChain is an object provided by the servlet container to the developer * giving a view into the invocation chain of a filtered request for a resource. Filters * use the FilterChain to invoke the next filter in the chain, or if the calling filter * is the last filter in the chain, to invoke the resource at the end of the chain. * **/ public interface FilterChain { /** * Causes the next filter in the chain to be invoked, or if the calling filter is the last filter * in the chain, causes the resource at the end of the chain to be invoked. * */ public void doFilter ( ServletRequest request, ServletResponse response ) throws IOException, ServletException; }
2.1.3、destroy()
在Web容器卸载 Filter 对象之前被调用。该方法在Filter的生命周期中仅执行一次。在这个方法中,可以释放过滤器使用的资源。
2.2、Filter链及其调用顺序
【Filter链】在一个web应用中,可以开发编写多个Filter,这些Filter组合起来称之为一个Filter链。
【Filter链调用顺序】WEB服务器根据Filter在web.xml文件中的注册顺序,决定先调用哪个Filter。
【代码级别的执行顺序】当第一个Filter的doFilter方法被调用时,web服务器会创建一个代表Filter链的FilterChain对象传递给该方法。在doFilter方法中,开发人员如果调用了FilterChain对象的doFilter方法,则web服务器会检查FilterChain对象中是否还有filter,如果有,则调用第2个filter,如果没有,则调用目标资源。