一、基本概念

之前我们用一篇博文介绍了Servlet相关的知识,有了那篇博文的知识积淀,今天我们学习Filter将会非常轻松,因为Filter有很多地方和Servlet类似,下面在讲Filter的时候,就闲话不絮了。

Filter称之为过滤器,是用来做一些拦截的任务。比如客户端请求服务器的某个资源时(可以是Servlet、JSP、HTML等等),我们可以拦截。当服务器返回资源给客户端的时候,我们也可以拦截。这样我们就可以在调用资源之前和之后分别加入一些业务逻辑。

当我们对某个资源加上多个过滤器的时候,就形成了过滤链。请求(request)会依次通过链上的过滤器,响应(response)会依次以相反的顺序通过过滤器。

二、样例分析

和使用servlet一样,要使用filter只需要两步:1.编写自己的filter,实现javax.servlet.Filter。2.在web.xml中注册该filter。

TestFilter.java

 public class TestFilter implements Filter {
public TestFilter() {} public void init(FilterConfig fConfig) throws ServletException {} public void destroy() {} public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
System.out.println("before doFilter");
chain.doFilter(request, response);
System.out.println("after doFilter");
}
}

web.xml

 <filter>
<filter-name>TestFilter</filter-name>
<filter-class>com.nantang.filter.TestFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>TestFilter</filter-name>
<url-pattern>/test</url-pattern>
</filter-mapping>

假定我们在本机部署应用,应用上下文路径是/demo,那么在浏览器里面输入http://localhost:8080/demo/test。则在控制台会输出:"before doFilter"和"after doFilter"。这是我们的请求和响应受到了拦截,在调用具体的Servlet或其他资源前后执行了我们编写的逻辑(例子中就是往控制台打印信息)。

这里需要注意的是,filter可以对url进行过滤,也可以针对具体的servlet进行过滤,只需要制定servlet的名称,如:

 <filter-mapping>
<filter-name>TestFilter</filter-name>
<servlet-name>TestServlet</servlet-name>
</filter-mapping>

三、源码分析

我们自己编写的filter都需要实现javax.servlet.Filter接口,下面我们看一下Filter接口的继承层级,并逐一分析。

1 FilterConfig

当容器去初始化一个filter的时候,就会根据web.xml文件的配置和当前的运行环境去构造一个FilterCongif实例并传给filter。所以一个filter对应一个FilterConfig实例。

 public interface FilterConfig {

     public String getFilterName();

     public ServletContext getServletContext();

     public String getInitParameter(String name);

     public Enumeration getInitParameterNames();
}

getFilterName方法返回我们在web.xml里面配置的名称。

getServletContext返回ServletContext实例,这个和之前介绍Servlet的时候讲到的是一个东西。一个应用就一个ServletContext实例。

getInitParameter和getInitParameterNames和Servlet的类似。就是获取在web.xml里面配置的初始化参数,如:

 <filter>
<filter-name>TestFilter</filter-name>
<filter-class>com.nantang.filter.TestFilter</filter-class>
<init-param>
<param-name>param1</param-name>
<param-value>1</param-value>
</init-param>
<init-param>
<param-name>param2</param-name>
<param-value>2</param-value>
</init-param>
</filter>

2 FilterChain

FilterChain就是我们上面说的过滤链,当请求或响应被filter拦截时,容器提供FilterChain实例给filter让其使用。

 public interface FilterChain {

     public void doFilter ( ServletRequest request, ServletResponse response ) throws IOException, ServletException;
}

FilterChain里面就一个方法doFilter,这个方法就是调用过滤链的下一个filter,如果当前filter是链中最后的一个,则跳转至请求的资源或返回响应给客户端。

3 Filter

Filter里面就三个方法,也就是它的生命周期。和Servlet类似。

 public interface Filter {

     public void init(FilterConfig filterConfig) throws ServletException;

     public void doFilter ( ServletRequest request, ServletResponse response, FilterChain chain ) throws IOException, ServletException;

     public void destroy();
}

3.1 init

filter的初始化方法,跟servlet一样在其生命周期内只会被执行一次。但是filter初始化的时机和servlet不一样,当servlet容器(比如Tomcat)启动完成后就会检索web.xml里面配置的filter,从上往下依次回调每个filter的init方法对其进行初始化。(这里的filterConfig参数是容器构造并传入的。)

3.2 doFilter

实现拦截逻辑的地方,比如一个请求被拦截,这里可以在调用具体资源之前编写一些业务逻辑。然后调用chain.doFilter流转到后置filter,如果当前filter是链中最后的一个,则跳转至请求的资源。当chain.doFilter执行完成后,可以再写一些业务逻辑。然后容器将执行权流转到前置filter,如果当前filter是链中最前的一个,则将响应返回给客户端。(这里的参数chain是容器构造并传入的。)

3.3 destory

和servlet的destroy方法同样的道理,当servlet容器关闭或需要更多内存的时候,会销毁filter。这个方法就使得servlet容器拥有回收资源的能力。

同样地,destroy方法在filter的生命周期中只会被调用一次。

四、总结

到这里filter就算结束了,我们可以发现filter的执行模型和servlet很类似,都是servlet容器在调度。整个生命周期都是容器在管控。

作者:南唐三少
出处:http://www.cnblogs.com/nantang

如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮,您的“推荐”将是我们最大的写作动力!欢迎各位转载,但是未经作者本人同意,转载文章之后必须在文章页面明显位置给出作者和原文链接,否则保留追究法律责任的权利。

最新文章

  1. Aes 加解密算法
  2. 一些MEL命令
  3. js-jQuery对象与dom对象相互转换
  4. 封装cookie
  5. 131. Palindrome Partitioning
  6. DataTable,DataSet,DataRow与DataView
  7. MemCachedClient数据写入的三个方法
  8. SAP字符串处理
  9. Zookeeper技术分享
  10. pwn入门题x2
  11. Git在已有的分支上新建个人分支开发
  12. [蓝桥杯]PREV-13.历届试题_网络寻路
  13. python--私有属性--私有方法
  14. 如何实现用将富文本编辑器内容保存为txt文件并展示
  15. Java 里如何实现线程间通信(转载)
  16. [Codeforces757G]Can Bash Save the Day?——动态点分治(可持久化点分树)
  17. 干掉hao123劫持浏览器主页
  18. SQL注入之PHP-MySQL实现手工注入-字符型
  19. 4星|《流量池》:Luckin Coffee营销操盘手经验谈
  20. fiddler抓包工具教程

热门文章

  1. MVC Core 网站开发(Ninesky) 1、创建项目
  2. Android 6.0 权限知识学习笔记
  3. Android -- 真正的 高仿微信 打开网页的进度条效果
  4. 记录一则Linux SSH的互信配置过程
  5. Python(九) Python 操作 MySQL 之 pysql 与 SQLAchemy
  6. BPM配置故事之案例2-文本默认值
  7. 编译器开发系列--Ocelot语言7.中间代码
  8. ios 类似微信红点显示功能
  9. 从零自学Hadoop(22):HBase协处理器
  10. 整体二分QAQ