拦截器(Interceptor)与过滤器(Filter)的区别

本贴最后更新于 1675 天前,其中的信息可能已经渤澥桑田

一、概述

过滤器,是在 java web 中将传入的 request、response 提前过滤掉一些信息,或者提前设置一些参数。然后再传入 Servlet 或 Struts2 的 action 进行业务逻辑处理。比如过滤掉非法 url(不是 login.do 的地址请求,如果用户没有登陆都过滤掉),或者在传入 Servlet 或 Struts2 的 action 前统一设置字符集,或者去除掉一些非法字符。

拦截器,是面向切面编程(AOP,Aspect Oriented Program)的。就是在 Service 或者一个方法前调用一个方法,或者在方法后调用一个方法。比如动态代理就是拦截器的简单实现,在调用方法前打印出字符串(或者做其它业务逻辑的操作),也可以在调用方法后打印出字符串,甚至在抛出异常的时候做业务逻辑的操作。

二、对比

通俗理解:

(1)过滤器(Filter):当你有一堆东西的时候,你只希望选择符合你要求的某一些东西。定义这些要求的工具,就是过滤器。(理解:就是一堆字母中取一个 B)
(2)拦截器(Interceptor):在一个流程正在进行的时候,你希望干预它的进展,甚至终止它进行,这是拦截器做的事情。(理解:就是一堆字母中,干预它,通过验证的少点,顺便干点别的东西)

主要区别:

  • 拦截器是基于 Java 的反射机制的,而过滤器是基于函数回调。
  • 拦截器不依赖于 servlet 容器,过滤器依赖于 servlet 容器。
  • 拦截器只能对 action 请求起作用,而过滤器则可以对几乎所有的请求起作用。
  • 拦截器可以访问 action 上下文、值栈里的对象,而过滤器不能访问。
  • 在 action 的生命周期中,拦截器可以多次被调用,而过滤器只能在容器初始化时被调用一次
  • 拦截器可以获取 IOC 容器中的各个 bean(基于 FactoryBean 接口 ),而过滤器就不行,在拦截器里注入一个 service,可以调用业务逻辑。

本质区别:

从灵活性上说拦截器功能更强大些,Filter 能做的事情它都能做,而且可以在请求前,请求后执行,比较灵活。Filter 主要是针对 URL 地址做一个编码的事情、过滤掉没用的参数、安全校验(比较泛的,比如登录不登录之类),太细的活儿还是建议用 interceptor。具体还得根据不同情况选择合适的。

image.png

执行顺序 :

过滤前-----拦截前-----Action 处理-----拦截后-----过滤后。
个人认为过滤是一个横向的过程,首先把客户端提交的内容进行过滤(例如未登录用户不能访问内部页面的处理);过滤通过后,拦截器将进行用户提交数据的验证,做一些前期的数据处理;接着把处理后的数据发给对应的 Action,Action 处理完成返回后,拦截器还可以做些其他事情,再向上返回到过滤器的后续操作。
image.png

过滤器(Filter)是在请求进入容器后,但还未进入 Servlet 之前进行预处理的。请求结束返回也是,是在 Servlet 处理完后,返回给前端之前。所以过滤器(Filter)的 doFilter(ServletRequest request, ServletResponse response, FilterChain chain ) 的入参是 ServletRequest ,而不是 httpservletrequest。因为过滤器是在 httpservlet 之前。

@Override
public void init(FilterConfig arg0) throws ServletException {

}
 @Override 
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
        System.out.println("before...");
        chain.doFilter(request, response);
        System.out.println("after...");
 }
@Override
public void destroy() {

}

Filter 跟 Servlet 一样都是由服务器负责创建和销毁的。

在 web 应用程序启动时,服务器会根据应用程序的 web.xml 文件中的配置信息调用 public void init(FilterConfig filterConfig) throws ServletException 方法来初始化 Filter;在 web 应用程序被移除或者是服务器关闭时,会调用 public void destroy() 来销毁 Filter。

在一个应用程序中一个 Filter 只会被创建和销毁一次。在初始化之后,Filter 中声明了 public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException 方法,用来实现一些需要在拦截完成之后的业务逻辑。

注意到上面的 doFilter() 方法的参数中,有 FilterChain chain 这个参数,它是传递过来的拦截链对象,里面包含了用户定义的一系列的拦截器,这些拦截器根据其在 web.xml 中定义的顺序依次被执行。当用户的信息验证通过或者当前拦截器不起作用时,我们可以执行 chain.doFilter(request, response); 方法来跳过当前拦截器来执行拦截器链中的下一个拦截器。chain.doFilter(request, response); 这个方法的调用作为分水岭。事实上调用 Servlet 的 doService() 方法是在 chain.doFilter(request, response); 这个方法中进行的。

三、拦截器与过滤器使用场景:

SpringMVC 的处理器拦截器类似于 Servlet 开发中的过滤器 Filter,用于对处理器进行预处理和后处理。

1、日志记录:记录请求信息的日志,以便进行信息监控、信息统计、计算 PV(Page View)等。
2、权限检查:如登录检测,进入处理器检测检测是否登录,如果没有直接返回到登录页面;
3、性能监控:有时候系统在某段时间莫名其妙的慢,可以通过拦截器在进入处理器之前记录开始时间,在处理完后记录结束时间,从而得到该请求的处理时间(如果有反向代理,如 apache 可以自动记录);
4、通用行为:读取 cookie 得到用户信息并将用户对象放入请求,从而方便后续流程使用,还有如提取 Locale、Theme 信息等,只要是多个处理器都需要的即可使用拦截器实现。
5、OpenSessionInView:如 hibernate,在进入处理器打开 Session,在完成后关闭 Session。

四、补充说明:

Spring 的拦截器与 Servlet 的 Filter 有相似之处,比如二者都是 AOP 编程思想的体现,都能实现权限检查、日志记录等。不同的是:

  • 使用范围不同:Filter 是 Servlet 规范规定的,只能用于 Web 程序中。而拦截器既可以用于 Web 程序,也可以用于 Application、Swing 程序中。
  • 规范不同:Filter 是在 Servlet 规范中定义的,是 Servlet 容器支持的。而拦截器是在 Spring 容器内的,是 Spring 框架支持的。
  • 使用的资源不同:同其他的代码块一样,拦截器也是一个 Spring 的组件,归 Spring 管理,配置在 Spring 文件中,因此能使用 Spring 里的任何资源、对象,例如 Service 对象、数据源、事务管理等,通过 IOC 注入到拦截器即可;而 Filter 则不能。
  • 深度不同:Filter 在只在 Servlet 前后起作用。而拦截器能够深入到方法前后、异常抛出前后等,因此拦截器的使用具有更大的弹性。所以在 Spring 构架的程序中,要优先使用拦截器。

实际上 Filter 和 Servlet 极其相似,区别只是 Filter 不能直接对用户生成响应。实际上 Filter 里 doFilter()方法里的代码就是从多个 Servlet 的 service()方法里抽取的通用代码,通过使用 Filter 可以实现更好的复用。
  
Filter 是一个可以复用的代码片段,可以用来转换 Http 请求、响应和头信息。Filter 不像 Servlet,它不能产生一个请求或者响应,它只是修改对某一资源的请求,或者修改从某一资源的响应。

JSR 中说明的是,按照多个匹配的 Filter,是按照其在 web.xml 中配置的顺序来执行的。所以这也就是,把自己的 Filter 或者其他的 Filter(比如 UrlRewrite 的 Filter)放在 Struts2 的 DispatcherFilter 的前面的原因。因为它们需要在请求被 Struts2 框架处理之前,做一些前置的工作。

当 Filter 被调用,并且进入了 Struts2 的 DispatcherFilter 中后,Struts2 会按照在 Action 中配置的 Interceptor Stack 中的 Interceptor 的顺序,来调用 Interceptor。

作者:MChopin
链接:https://www.jianshu.com/p/cf088baa9b04
来源:简书

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...