聊聊java 过滤器、监听器、拦截器的区别(终结篇)

过滤器、监听器、拦截器概念

概念

1、servlet:servlet是一种运行服务器端的java应用程序,具有独立于平台和协议的特性,

可以动态生成web页面它工作在客户端请求与服务器响应的中间层;

2、filter:filter是一个可以复用的代码片段,可以用来转换HTTP请求,响应和头信息。

它不能产生一个请求或者响应,它只是修改对某一资源的请求或者响应;

3、listener:监听器,通过listener可以坚挺web服务器中某一执行动作,并根据其要求作出相应的响应。

就是在application,session,request三个对象创建消亡或者往其中添加修改删除属性时自动执行代码的功能组件;

4、interceptor:拦截器是对过滤器更加细化的应用,他不仅可以应用在service方法前后还可以应用到其他方法的前后 拦截器;

5、servlet,filter,listener是配置到web.xml中,interceptor不配置到web.xml中,struts的拦截器配置到struts。xml中。

spring的拦截器配置到spring.xml中;

过滤器和拦截器的区别

先说最易混淆的过滤器和拦截器的区别:

1、拦截器是基于java的反射机制的,而过滤器是基于函数回调。

2、拦截器不依赖与servlet容器,过滤器依赖与servlet容器。

3、拦截器只能对action请求起作用,而过滤器则可以对几乎所有的请求起作用。

4、拦截器可以访问action上下文、值栈里的对象,而过滤器不能访问。

5、在action的生命周期中,拦截器可以多次被调用,而过滤器只能在容器初始化时被调用一次。

6、拦截器可以获取IOC容器中的各个bean,而过滤器就不行,这点很重要,在拦截器里注入一个service,可以调用业务逻辑。

过滤器、监听器、拦截器的生命周期

1、servlet

servle的生命周期开始于被装入web服务器的内存中,并在web服务终止或者重新装入servlet的时候结束;

servlet一旦被装入web服务器,一般不会从web服务器内存中删除;直到web服务器关闭;

装入:启动服务器时加载servlet的实例;

初始化:web服务器接收到请求时,或者两者之间的某个时刻启动,调用init()

调用:从第一次到以后的多次访问,都只调用doGet()或dopost)()方法;

销毁;停止服务器时调用destroy()方法,销毁实例;

2、filter

需要实现javax.servlet包的Filter接口的三个方法init(),doFilter(),destroy();

加载:启动服务器时加载过滤器的实例,并调用init()方法;

调用:每次请求的时候只调用方法doFilter()进行处理;

销毁:服务器关闭前调用destroy()方法,销毁实例;

3、listener

web.xml的加载顺序是:context-param->listener->filter->servlet

4、interceptor

加载配置文件后初始化拦截器,当有对action的请求的时候,调用interceptor方法,最后也是根据服务器停止进行销毁;

过滤器、监听器、拦截器的职责

1、servlet

创建并返回一个包含基于客户请求性质的动态内容的完整的html页面

创建可嵌入到现有的html页面中的一部分html页面(html片段)

读取客户端发来的隐藏数据

读取客户端发来的显示数据

与其他服务器资源(包括数据库和java的应用程序)进行通信

2、filter

filter能够在一个请求到达servlet之前预处理用户请求,也可以在离开servlet时处理http响应:

在执行servlet之前,首先执行filter程序,并为之做一些预处理工作;

在servlet被调用之后截获servlet的执行

3、listener

servlet2.4规范提供了8个listener接口,可以将其分为三类,分别如下;

第一类:与HttpContext有关的listener接口,包括:ServletContextListener、ServletContextAttributeListener

第二类:与HttpSession有关的listner接口。包括:HttpSessionListener、HttpSessionAttributeListener、 HttpSessionBindingListener、 HttpSessionActivationListener、

第三类:与ServletRequest有关的Listener接口,包括:ServletRequestListener、ServletRequestAttributeListener

4、interceptor

与过滤器类似,通过层层拦截,处理用户的请求和响应;

过滤器、监听器、拦截器的图解

这个很重要,注意在shiro或者springsecurity配置安全相关的时候,如果异常无法捕获,往往就是web请求顺序导致的,

比如你配置了全局异常,但是异常请求如果没有到达controller层,那么全局异常依然无法捕捉到这类异常,因为请求都没有发到控制层(servlet那一层),

在Filter层已经报权限不足异常那么直接就返回了,所以在前后端分离传递jwt配置的token校验时,如果异常返回的403无法以想要的json3段式或者4段式返回。

同样AOP日志也是无法捕获的,包括各种增强,连环绕增强都无法捕获这个安全框架的403异常

1、servlet:

2、filter

3、listener

4、interceptor

补充:拦截器(Interceptor)和过滤器(Filter)的执行顺序和区别

一、引言

本来想记录一下关于用户登陆和登陆之后的权限管理、菜单管理的问题,想到解决这个问题用到Interceptor,但想到了Interceptor,就想到了Filter,于是就想说一下它们的执行顺序和区别。

关于Interceptor解决权限和菜单管理的问题,在放在下一篇写吧,就酱紫。

二、区别

1、过滤器(Filter)

首先说一下Filter的使用地方,我们在配置web.xml时,总会配置下面一段设置字符编码,不然会导致乱码问题:

<filter>
 <filter-name>encoding</filter-name>
 <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
 <init-param>
 <param-name>encoding</param-name>
 <param-value>UTF-8</param-value>
 </init-param>
 <init-param>
 <param-name>forceEncoding</param-name>
 <param-value>true</param-value>
 </init-param>
</filter>
<filter-mapping>
 <filter-name>encoding</filter-name>
 <servlet-name>/*</servlet-name>
</filter-mapping>

配置这个地方的目的,是让所有的请求都需要进行字符编码的设置,下面来介绍一下Filter。

(1)过滤器(Filter):

它依赖于servlet容器。在实现上,基于函数回调,它可以对几乎所有请求进行过滤,但是缺点是一个过滤器实例只能在容器初始化时调用一次。

使用过滤器的目的,是用来做一些过滤操作,获取我们想要获取的数据,比如:在Javaweb中,对传入的request、response提前过滤掉一些信息,或者提前设置一些参数,然后再传入servlet或者Controller进行业务逻辑操作。

通常用的场景是:在过滤器中修改字符编码(CharacterEncodingFilter)、在过滤器中修改HttpServletRequest的一些参数(XSSFilter(自定义过滤器)),如:过滤低俗文字、危险字符等。

2、拦截器(Interceptor)

拦截器的配置一般在SpringMVC的配置文件中,使用Interceptors标签,具体配置如下:

<mvc:interceptors>
 <mvc:interceptor>
 <mvc:mapping path="/**" />
 <bean class="com.scorpios.atcrowdfunding.web.LoginInterceptor"></bean>
 </mvc:interceptor>
 <mvc:interceptor>
 <mvc:mapping path="/**" />
 <bean class="com.scorpios.atcrowdfunding.web.AuthInterceptor"></bean>
 </mvc:interceptor>
</mvc:interceptors>

(2)拦截器(Interceptor):它依赖于web框架,在SpringMVC中就是依赖于SpringMVC框架。

在实现上,基于Java的反射机制,属于面向切面编程(AOP)的一种运用,就是在service或者一个方法前,调用一个方法,或者在方法后,调用一个方法,比如动态代理就是拦截器的简单实现,在调用方法前打印出字符串(或者做其它业务逻辑的操作),也可以在调用方法后打印出字符串,甚至在抛出异常的时候做业务逻辑的操作。

由于拦截器是基于web框架的调用,因此可以使用Spring的依赖注入(DI)进行一些业务操作,同时一个拦截器实例在一个controller生命周期之内可以多次调用。

但是缺点是只能对controller请求进行拦截,对其他的一些比如直接访问静态资源的请求则没办法进行拦截处理。

三、代码

下面在一个项目中我们使用既有多个过滤器,又有多个拦截器,并观察它们的执行顺序:

(1)第一个过滤器:

public class TestFilter1 implements Filter {
 @Override
 protected void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
 //在DispatcherServlet之前执行
 System.out.println("############TestFilter1 doFilterInternal executed############");
 filterChain.doFilter(request, response);
 //在视图页面返回给客户端之前执行,但是执行顺序在Interceptor之后
 System.out.println("############TestFilter1 doFilter after############");
 }
} 

(2)第二个过滤器:

public class TestFilter2 implements Filter { 

 @Override
 protected void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
 //在DispatcherServlet之前执行
 System.out.println("############TestFilter2 doFilterInternal executed############");
 filterChain.doFilter(request, response);
 //在视图页面返回给客户端之前执行,但是执行顺序在Interceptor之后
 System.out.println("############TestFilter2 doFilter after############");
 }
} 

(3)在web.xml中注册这两个过滤器:

 <!-- 自定义过滤器:testFilter1 -->
 <filter>
  <filter-name>testFilter1</filter-name>
  <filter-class>com.scorpios.filter.TestFilter1</filter-class>
 </filter>
 <filter-mapping>
  <filter-name>testFilter1</filter-name>
  <url-pattern>/*</url-pattern>
 </filter-mapping>
 <!-- 自定义过滤器:testFilter2 -->
 <filter>
  <filter-name>testFilter2</filter-name>
  <filter-class>com.scorpios.filter.TestFilter2</filter-class>
 </filter>
 <filter-mapping>
  <filter-name>testFilter2</filter-name>
  <url-pattern>/*</url-pattern>
 </filter-mapping> 

再定义两个拦截器:

(4)第一个拦截器:

public class BaseInterceptor implements HandlerInterceptor{ 

 /**
 * 在DispatcherServlet之前执行
 * */
 public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2) throws Exception {
 System.out.println("************BaseInterceptor preHandle executed**********");
 return true;
 } 

 /**
 * 在controller执行之后的DispatcherServlet之后执行
 * */
 public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3) throws Exception {
 System.out.println("************BaseInterceptor postHandle executed**********");
 } 

 /**
 * 在页面渲染完成返回给客户端之前执行
 * */
 public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3)
  throws Exception {
 System.out.println("************BaseInterceptor afterCompletion executed**********");
 }
} 

(5)第二个拦截器:

public class TestInterceptor implements HandlerInterceptor {
 public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2) throws Exception {
 System.out.println("************TestInterceptor preHandle executed**********");
 return true;
 } 

 public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3) throws Exception {
 System.out.println("************TestInterceptor postHandle executed**********");
 } 

 public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3) throws Exception {
 System.out.println("************TestInterceptor afterCompletion executed**********");
 }
} 

(6)、在SpringMVC的配置文件中,加上拦截器的配置:

 <!-- 拦截器 -->
 <mvc:interceptors>
 <!-- 对所有请求都拦截,公共拦截器可以有多个 -->
 <bean name="baseInterceptor" class="com.scorpios.interceptor.BaseInterceptor" /> 

 <mvc:interceptor>
 <!-- 对/test.html进行拦截 -->
  <mvc:mapping path="/test.html"/>
  <!-- 特定请求的拦截器只能有一个 -->
  <bean class="com.scorpios.interceptor.TestInterceptor" />
 </mvc:interceptor>
 </mvc:interceptors> 

(7)、定义一个Controller控制器:

package com.scorpios.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView; 

@Controller
public class TestController {
 @RequestMapping("/test")
 public ModelAndView handleRequest(){
 System.out.println("---------TestController executed--------");
 return new ModelAndView("test");
 }
} 

(8)、测试结果:

启动测试项目,地址如下:http://www.localhost:8080/demo,可以看到控制台中输出如下:

这就说明了过滤器的运行是依赖于servlet容器,跟springmvc等框架并没有关系。并且,多个过滤器的执行顺序跟xml文件中定义的先后关系有关。

接着清空控制台,并访问:http://www.localhost:8080/demo/test,再次看控制台的输出:

从这个控制台打印输出,就可以很清晰地看到有多个拦截器和过滤器存在时的整个执行顺序了。当然,对于多个拦截器它们之间的执行顺序跟在SpringMVC的配置文件中定义的先后顺序有关。

四、总结

对于上述过滤器和拦截器的测试,可以得到如下结论:

(1)、Filter需要在web.xml中配置,依赖于Servlet;

(2)、Interceptor需要在SpringMVC中配置,依赖于框架;

(3)、Filter的执行顺序在Interceptor之前,具体的流程见下图;

(4)、两者的本质区别:拦截器(Interceptor)是基于Java的反射机制,而过滤器(Filter)是基于函数回调。

从灵活性上说拦截器功能更强大些,Filter能做的事情,都能做,而且可以在请求前,请求后执行,比较灵活。

Filter主要是针对URL地址做一个编码的事情、过滤掉没用的参数、安全校验(比较泛的,比如登录不登录之类),太细的话,还是建议用interceptor。不过还是根据不同情况选择合适的。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。如有错误或未考虑完全的地方,望不吝赐教。

(0)

相关推荐

  • Java使用Gateway自定义负载均衡过滤器

    背景 最近项目中需要上传视频文件,由于视频文件可能会比较大,但是我们应用服务器tomcat设置单次只支持的100M,因此决定开发一个分片上传接口. 把大文件分成若干个小文件上传.所有文件上传完成后通过唯一标示进行合并文件. 我们的开发人员很快完成了开发,并在单元测试中表现无误.上传代码到测试环境,喔嚯!!!出错了. 经过一段时间的辛苦排查终于发现问题,测试环境多实例,分片上传的接口会被路由到不同的实例,导致上传后的分片文件在不同的机器,那么也就无法被合并. 知道了原因就好解决,经过一系列的过程最

  • 布隆过滤器的原理以及java 简单实现

    一.布隆过滤器 布隆过滤器(Bloom Filter)是1970年由布隆提出的.它实际上是一个很长的二进制向量和一系列随机映射函数.布隆过滤器可以用于检索一个元素是否在一个集合中.它的优点是空间效率和查询时间都远远超过一般的算法,缺点是有一定的误识别率和删除困难. 如果想判断一个元素是不是在一个集合里,一般想到的是将集合中所有元素保存起来,然后通过比较确定.链表.树.散列表(又叫哈希表,Hash table)等等数据结构都是这种思路.但是随着集合中元素的增加,我们需要的存储空间越来越大.同时检索

  • Java中的拦截器、过滤器、监听器用法详解

    本文实例讲述了Java中的拦截器.过滤器.监听器用法.分享给大家供大家参考,具体如下: 一.拦截器 :是在面向切面编程的就是在你的service或者一个方法,前调用一个方法,或者在方法后调用一个方法比如动态代理就是拦截器的简单实现,在你调用方 法前打印出字符串(或者做其它业务逻辑的操作),也可以在你调用方法后打印出字符串,甚至在你抛出异常的时候做业务逻辑的操作. 1.Struts2拦截器是在访问某个Action或Action的某个方法,字段之前或之后实施拦截,并且Struts2拦截器是可插拔的,

  • Java使用过滤器防止SQL注入XSS脚本注入的实现

    前几天有个客户在系统上写了一段html语句,打开页面就显示一张炒鸡大的图片,影响美观.后来仔细想想,幸亏注入的仅仅是html语句,知道严重性后,马上开始一番系统安全配置. 一. 定义过滤器 package com.cn.unit.filter; import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; i

  • java过滤器中Filter的ChainFilter过滤链

    1.什么是过滤器? 在客户端到服务器的过程中,当发送请求时,如果有不符合的信息将会被filter进行拦截,如果符合则会进行放行,在服务器给客户端响应时也会进行判断 如果有不符合的信息将会被filter进行拦截,如果符合则会进行放行. OOP:Java面向对象编程,抽象.封装.继承.多态. AOP:面向切面编程,过滤器就是一个面向切面的编程思想. AOP是sun公司srvlet2.3版本之后推出的新功能,在2.3之前的版本没有该功能,定义一个过滤器需要实现(implement)Filter接口,这

  • 浅析JAVA中过滤器、监听器、拦截器的区别

    1.过滤器:所谓过滤器顾名思义是用来过滤的,在java web中,你传入的request,response提前过滤掉一些信息,或者提前设置一些参数,然后再传入servlet或者struts的action进行业务逻辑,比如过滤掉非法url(不是login.do的地址请求,如果用户没有登陆都过滤掉),或者在传入servlet或者struts的action前统一设置字符集,或者去除掉一些非法字符(聊天室经常用到的,一些骂人的话).filter 流程是线性的, url传来之后,检查之后,可保持原来的流程

  • 聊聊java 过滤器、监听器、拦截器的区别(终结篇)

    过滤器.监听器.拦截器概念 概念 1.servlet:servlet是一种运行服务器端的java应用程序,具有独立于平台和协议的特性, 可以动态生成web页面它工作在客户端请求与服务器响应的中间层: 2.filter:filter是一个可以复用的代码片段,可以用来转换HTTP请求,响应和头信息. 它不能产生一个请求或者响应,它只是修改对某一资源的请求或者响应: 3.listener:监听器,通过listener可以坚挺web服务器中某一执行动作,并根据其要求作出相应的响应. 就是在applica

  • 通过实例解析java过滤器和拦截器的区别

    区别 1.使用范围和规范不同 filter是servlet规范规定的,只能用在web程序中. 拦截器即可以用在web程序中, 也可以用于application, swing程序中, 是Spring容器内的, 是Spring框架支持的 2.触发时机不同 顺序: Filter-->Servlet-->Interceptor-->Controller 过滤器是在请求进入容器后,但请求进入servlet之前进行预处理的.请求结束返回也是,是在servlet处理完后,返回给前端之前过滤器处理. 拦

  • struts2过滤器和拦截器的区别分析

    本文分析了struts2过滤器和拦截器的区别.分享给大家供大家参考,具体如下: 一.本质区别: 1. 拦截器是基于java的反射机制的,而过滤器是基于函数回调. 2. 拦截器不依赖与servlet容器,过滤器依赖与servlet容器. 3. 拦截器只能对action请求起作用,而过滤器则可以对几乎所有的请求起作用. 4. 拦截器可以访问action上下文.值栈里的对象,而过滤器不能访问. 5. 在action的生命周期中,拦截器可以多次被调用,而过滤器只能在容器初始化时被调用一次 二.使用区别:

  • SpringBoot实现过滤器、拦截器与切片的实现和区别

    Q:使用过滤器.拦截器与切片实现每个请求耗时的统计,并比较三者的区别与联系 过滤器Filter 过滤器概念 Filter是J2E中来的,可以看做是 Servlet 的一种"加强版",它主要用于对用户请求进行预处理和后处理,拥有一个典型的 处理链 .Filter也可以对用户请求生成响应,这一点与Servlet相同,但实际上很少会使用Filter向用户请求生成响应.使用Filter完整的流程是:Filter对用户请求进行预处理,接着将请求交给Servlet进行预处理并生成响应,最后Filt

  • SpringBoot面试突击之过滤器和拦截器区别详解

    目录 实现过滤器和拦截器 a) 实现过滤器 b) 实现拦截器 过滤器 VS 拦截器 1.出身不同 2.触发时机不同 3.实现不同 4.支持的项目类型不同 5.使用的场景不同 总结 实现过滤器和拦截器 首先,我们先来看一下二者在 Spring Boot 项目中的具体实现,这对后续理解二者的区别有很大的帮助. a) 实现过滤器 过滤器可以使用 Servlet 3.0 提供的 @WebFilter 注解,配置过滤的 URL 规则,然后再实现 Filter 接口,重写接口中的 doFilter 方法,具

  • SpringBoot使用过滤器、拦截器和监听器的案例代码(Springboot搭建java项目)

    目录 SpringBoot使用过滤器.拦截器和监听器 一.SpringBoot使用过滤器 Spring boot过滤器的使用(两种方式) 方式一: 方式二: 二.SpringBoot使用拦截器 三.过滤器和拦截器的执行顺序 四.SpringBoot使用监听器 1.统计网站最多在线人数监听器的例子 2.springboot监听器的使用(以实现异步Event监听为例子) SpringBoot使用过滤器.拦截器和监听器 一.SpringBoot使用过滤器 Spring boot过滤器的使用(两种方式)

  • SpringBoot 过滤器、拦截器、监听器对比及使用场景分析

    一.关系图理解 二.区别 1.过滤器 过滤器是在web应用启动的时候初始化一次, 在web应用停止的时候销毁 可以对请求的URL进行过滤, 对敏感词过滤 挡在拦截器的外层 实现的是 javax.servlet.Filter 接口 ,是 Servlet 规范的一部分 在请求进入容器后,但在进入servlet之前进行预处理,请求结束是在servlet处理完以后 依赖Web容器 会多次执行 过滤器简介 过滤器的英文名称为 Filter, 是 Servlet 技术中最实用的技术.如同它的名字一样,过滤器

  • 过滤器 和 拦截器的 6个区别(别再傻傻分不清了)

    周末有个小伙伴加我微信,向我请教了一个问题:老哥,过滤器 (Filter) 和 拦截器 (Interceptor) 有啥区别啊? 听到题目我的第一感觉就是:简单! 毕竟这两种工具开发中用到的频率都相当高,应用起来也是比较简单的,可当我准备回复他的时候,竟然不知道从哪说起,支支吾吾了半天,场面炒鸡尴尬有木有,工作这么久一个基础问题答成这样,丢了大人了. 平时觉得简单的知识点,但通常都不会太关注细节,一旦被别人问起来,反倒说不出个所以然来. 归根结底,还是对这些知识了解的不够,一直停留在会用的阶段,

随机推荐