在Spring MVC应用中,过滤器(Filter)和拦截器(Interceptor)都是用来处理请求的组件,但它们的作用范围和执行时机有所不同。理解这两者的执行顺序对于设计Web应用程序非常重要。
一,过滤器 Filter
Filter(过滤器)是J2EE的规范,Servlet2.3开始引入/实现的是职责链模式。多个过滤器形成一个过滤器链。
实现Filter接口,分别有init()用于完成过滤器的初始化,destroy() 用于过滤器销毁前,完成某些资源的回收,doFilter()实现过滤功能,对每个请求增加额外的处理。基于 Servlet,通过函数回调方式实现,可以过滤请求和图片文件等,每个请求一个过滤器只能过滤一次。严格意义上讲,filter只是适用于web中,依赖于Servlet容器,利用Java的回调机制进行实现。
作用范围:过滤器是Servlet规范的一部分,因此它对所有进入容器的请求都有效,不仅仅是Spring MVC的请求。
执行时机:过滤器在请求到达DispatcherServlet之前执行,也可以在响应返回给客户端之前执行。
应用场景:
1,用户访问权限处理;
2,设置字符集乱码处理;
3,过滤敏感词汇、压缩响应信息
二,拦截器 Interceptor
拦截器 Interceptor基于SpringMVC,基于java 的反射机制,代理模式实现;java里的拦截器是动态拦截Action调用的对象。它提供了一种机制可以使开发者可以定义在一个action执行的前后执行的代码,也可以在一个action执行前阻止其执行,同时也提供了一种可以提取action中可重用部分的方式。
实现HandlerInterceptor接口有三个方法,分别为在业务处理器处理请求之前被调用(preHandle()),在业务处理器处理完请求后(postHandle()),完全处理完请求后被调用(afterCompletion())。只能拦截请求,可以访问上下文等对象,功能强大,一个请求可多次拦截。
作用范围:拦截器是Spring MVC特有的,只对通过DispatcherServlet的请求有效。
执行时机:拦截器是在请求被DispatcherServlet分发到具体的Controller方法前后执行。
应用场景:
1,全局日志管理
2,用户访问权限处理
三,AOP
是一种编程范式,它允许你定义切面(aspect),这些切面可以在方法调用之前、之后或环绕方法调用执行。AOP可以应用于任何Spring Bean的方法,而不仅仅限于Web请求。
AOP的执行时机取决于你定义的通知(advice)类型。Spring AOP支持以下几种通知类型:
前置通知 (Before Advice):在目标方法执行之前执行。
后置通知 (After Returning Advice):在目标方法成功执行之后执行。
异常通知 (After Throwing Advice):在目标方法抛出异常时执行。
最终通知 (After Advice):无论目标方法是否抛出异常,都会在方法执行后执行。
环绕通知 (Around Advice):可以在方法调用之前和之后执行自定义逻辑,可以决定是否继续执行方法。
四,过滤器和拦截器的区别
过滤器和拦截器,这两者在功能方面很类似,但是在具体技术实现方面,差距还是比较大的。
我们先理解一下AOP的概念,AOP不是一种具体的技术,而是一种编程思想。在面向对象编程的过程中,我们很容易通过继承、多态来解决纵向扩展。但是对于横向的功能,比如,在所有的service方法中开启事务,或者统一记录日志等功能,面向对象的是无法解决的。所以AOP——面向切面编程其实是面向对象编程思想的一个补充。
过滤器和拦截器都属于面向切面编程的具体实现。而两者的主要区别包括以下几个方面:
- Filter 是依赖于 Servlet容器,属于Servlet规范的一部分,而拦截器则是独立存在的,可以在任何情况下使用。
- Filter 的执行由 Servlet 容器回调完成,而拦截器通常通过动态代理(反射)的方式来执行。
- Filter 的生命周期由 Servlet 容器管理,而拦截器则可以通过IoC容器来管理,因此可以通过注入等方式来获取其他Bean的实例,因此使用会更方便。
- 在 action 的生命周期中,拦截器可以多次被调用,而过滤器只能在容器初始化时被调用一次。
五,拦截器和AOP区别
AOP是基于动态代理,生成一系列的代理类,效率较慢。而拦截器是基于SpringMVC,在SpringMVC工作流程中的执行方法action前后加上执行的代码,效率高。
六,执行顺序:
执行顺序:过滤器 -> 拦截器 -> AOP
当一个HTTP请求到达服务器时,它的处理流程大致如下:
1、过滤器链 (Filter Chain)
请求首先经过一系列的过滤器。这些过滤器按照它们在web.xml或通过Java配置注册的顺序依次执行。
如果某个过滤器中的doFilter()方法调用了chain.doFilter(request, response),则请求会传递给下一个过滤器;如果未调用,则请求将停止在此过滤器处,不会继续向下传递。
2、DispatcherServlet
一旦所有的过滤器都执行完毕并且没有中断请求链,请求就会到达DispatcherServlet。
DispatcherServlet负责根据请求URL找到合适的HandlerMapping来确定处理器(Controller)。
3、拦截器链 (Interceptor Chain)
在找到合适的处理器之后,但还没有调用处理器方法之前,请求会先经过一系列的拦截器。拦截器按preHandle()方法的顺序执行。只有当所有拦截器的preHandle()方法都返回true时,才会继续调用处理器的方法。
处理器方法执行完毕后,控制权回到拦截器链,此时会按照逆序执行各个拦截器的postHandle()方法。
最后,在视图渲染完成之后,会再次按照逆序执行各个拦截器的afterCompletion()方法。
4、响应
视图渲染完成后,响应开始回传。回传过程中,请求会再次经过之前的过滤器链,但这次是从最后一个过滤器往第一个过滤器方向执行每个过滤器的doFilter()方法后的代码块。
拦截方向和抛出异常方向图:
小结
拦截器相比过滤器有更细粒度的控制,依赖于Spring容器,可以在请求之前或之后启动,过滤器主要依赖于servlet,过滤器能做的,拦截器基本上都能做。
评论区