理解Servlet过滤器

一、过滤器的概念

  • 过滤器位于客户端和web应用程序之间,用于检查和修改两者之间流过的请求和响应。
  • 在请求到达Servlet/JSP之前,过滤器截获请求。
  • 在响应送给客户端之前,过滤器截获响应。
  • 多个过滤器形成一个过滤器链,过滤器链中不同过滤器的先后顺序由部署文件web.xml中过滤器映射<filter-mapping>的顺序决定。
  • 最先截获客户端请求的过滤器将最后截获Servlet/JSP的响应信息。

二、过滤器的链式结构

可以为一个Web应用组件部署多个过滤器,这些过滤器组成一个过滤器链,每个过滤器只执行某个特定的操作或者检查。这样请求在到达被访问的目标之前,需要经过这个过滤器链。

服务器会按照web.xml中过滤器定义的先后循序组装成一条链,然后一次执行其中的doFilter()方法。执行的顺序就如下图所示,执行第一个过滤器的chain.doFilter()之前的代码,第二个过滤器的chain.doFilter()之前的代码,请求的资源,第二个过滤器的chain.doFilter()之后的代码,第一个过滤器的chain.doFilter()之后的代码,最后返回响应。

filter

通常我们所访问的资源是一个servlet或jsp页面,而jsp其实是一个被封装了的servlet,于是我们就可以统一地认为我们每次访问的都是一个Servlet,而每当我们访问一个servlet时,web容器都会调用该Servlet的service方法去处理请求。而在service方法又会根据请求方式的不同(Get/Post)去调用相应的doGet()或doPost()方法,实际处理请求的就是这个doGet或doPost方法。写过servlet的朋友都应该知道,我们在doGet(或doPost)方法中是通过response.getWriter()得到客户端的输出流对象,然后用此对象对客户进行响应。

到这里我们就应该理解了过滤器的执行流程了:执行第一个过滤器的chain.doFilter()之前的代码——>第二个过滤器的chain.doFilter()之前的代码——>……——>第n个过滤器的chain.doFilter()之前的代码——>所请求servlet的service()方法中的代码——>所请求servlet的doGet()或doPost()方法中的代码——>第n个过滤器的chain.doFilter()之后的代码——>……——>第二个过滤器的chain.doFilter()之后的代码——>第一个过滤器的chain.doFilter()之后的代码。

三、过滤器的生命周期

1、实例化:Web容器在部署Web应用程序时对所有过滤器进行实例化。Web容器回调它的无参构造方法。

2、初始化:实例化完成之后,马上进行初始化工作。Web容器回调init()方法。

3、过滤:请求路径匹配过滤器的URL映射时。Web容器回调doFilter()方法——主要的工作方法。

4、销毁: Web容器在卸载Web应用程序前,Web容器回调destroy()方法。

四、实现过滤器

在Web应用中使用过滤器需要实现javax.servlet.Filter接口,实现Filter接口中所定义的方法,并在web.xml中部署过滤器。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class MyFilter implements Filter {

    public void init(FilterConfig fc) {
        //过滤器初始化代码
    }

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
        //在这里可以对客户端请求进行检查
        //沿过滤器链将请求传递到下一个过滤器。
        chain.doFilter(request, response);
        //在这里可以对响应进行处理

    }

    public void destroy( ) {
        //过滤器被销毁时执行的代码
    }

}

 

五、Servlet过滤器API

Servlet过滤器API包含了3个接口,它们都在javax.servlet包中,分别是Filter接口、FilterChain接口和FilterConfig接口。

1  public Interface Filter
所有的过滤器都必须实现Filter接口。该接口定义了init,doFilter0,destory()三个方法:

(1) public void init (FilterConfig filterConfig) throws   ServletException.
当开始使用servlet过滤器服务时,Web容器调用此方法一次,为服务准备过滤器;然后在需要使用过滤器的时候调用doFilter(),传送给此方法的FilterConfig对象,包含servlet过滤器的初始化参数。

(2)public void doFilter(ServletRequest request,ServletResponse response,FilterChain chain) throws java.io.IOException,ServletException.

每个过滤器都接受当前的请求和响应,且FilterChain过滤器链中的过滤器(应该都是符合条件的)都会被执行。doFilter方 法中,过滤器可以对请求和响应做它想做的一切,通过调用他们的方法收集数据,或者给对象添加新的行为。过滤器通过传送至此方法的FilterChain参数,调用chain.doFilterO将控制权传送给下一个过滤器。当这个调用返回后,过滤器可以在它的 Filter方法的最后对响应做些其他的工作。如果过滤器想要终止请求的处理或得到对响应的完全控制,则可以不调用下一个过滤器,而将其重定向至其它一些页面。当链中的最后一个过滤器调用chain.doFilterO方法时,将运行最初请求的Servlet。

(3)public void destroy()
一旦doFilterO方法里的所有线程退出或已超时,容器调用此方法。服务器调用destoryO以指出过滤器已结束服务,用于释放过滤器占用的资源。

2 public interface FilterChain

public void doFilter(ServletRequest request,ServletResponse response)

thlows java.io.IOException,ServletException

此方法是由Servlet容器提供给开发者的,用于对资源请求过滤链的依次调用,通过FilterChain调用过滤链中的下一个过滤   器,如果是最后一个过滤器,则下一个就调用目标资源。

3 public interface FilterConfig

FilterConfig接口检索过滤器名、初始化参数以及活动的Servlet上下文。该接口提供了以下4个方法:

(1)public java.1ang.String getFilterName0
返回web.xml部署文件中定义的该过滤器的名称。

(2)public ServletContext getServletContextO
返回调用者所处的servlet上下文。
(3)public java.1ang.String getlnitParameter(java.1ang.String name)
返回过滤器初始化参数值的字符串形式,当参数不存在时,返回nul1.name是初始化参数名。
(4)public java.util.Enumeration getlnitParameterNames()
以Enumeration形式返回过滤器所有初始化参数值,如果没有初始化参数,返回为空。

六、配置Servlet过滤器

过滤器通过 web.xml 文件中的两个 XML 标签来声明:

1、<filter> : 定义过滤器的名称,并且声明过滤器实现类和 init() 参数。
<filter-name> : 指定过滤器的名字;
<filter-class> : 指定过滤器类的类名,包括类的路径;
<init-param> : 为过滤器实例提供初始化参数,可以有多个;

2、<filter-mapping> : 将过滤器与 servlet 或 URL 模式相关联。
<filter-name> :  指定过滤器的名字,与<filter>中的子元素<filter-name>相对应;
<url-pattern> :  指定和过滤器关联的URL,为”/*”表示所有URL;

在web.xml中配置Servlet和Servlet过滤器,应该先声明过滤器元素,再声明Servlet元素。
两个或更多个过滤器应用到同一个资源,按照它们在配置文件中显示的先后次序调用它们。

1
2
3
4
5
6
7
8
  <filter>    
  <filter-name>FilterName</filter-name>    
  <filter-class>packageName.FilterName</filter-class>  
 </filter>  
 <filter-mapping>    
  <filter-name>FilterName</filter-name>    
  <url-pattern>/*</url-pattern>  
 </filter-mapping>

七、Servlet过滤器实现注意的细节

1.由于Filter、FilterConfig、FilterChain都是位于javax.servlet包下,并非HTTP包所特有的,
所以ServletRequest、ServletResponse在使用前都必须先转换成HttpServletRequest、HttpServletResponse再进行下一步操作。

2.在web.xml中配置Servlet和Servlet过滤器,应该先声明过滤器元素,再声明Servlet元素。

3.如果要在Servlet中观察过滤器生成的日志,应该确保在server.xml的localhost对应的<host>元素中配置如下<logger>元素:
<Logger className = “org.apache.catalina.logger.FileLogger”
directory = “logs”prefix = “localhost_log.”suffix=”.txt”
timestamp = “true”/>

 

除非注明,Coder文章均为原创,转载请以链接形式标明本文地址

本文地址:http://www.alonemonkey.com/servlet-filter.html

本文链接:http://www.alonemonkey.com/servlet-filter.html