转自:http://blog.csdn.net/chenleixing/article/details/44573495
过滤器和拦截器的区别:
- 拦截器是基于Java的反射机制的,而过滤器是基于函数回调。
- 拦截器不依赖与servlet容器,过滤器依赖与servlet容器。
- 拦截器只能对action请求起作用,而过滤器则可以对几乎所有的请求起作用。
- 拦截器可以访问action上下文、值栈里的对象,而过滤器不能访问。
- 在action的生命周期中,拦截器可以多次被调用,而过滤器只能在容器初始化时被调用一次。
- 拦截器可以获取IOC容器中的各个bean,而过滤器就不行,这点很重要,在拦截器里注入一个service,可以调用业务逻辑。
增加:2021/04/11 14:23:08
转自:https://blog.csdn.net/zzti_erlie/article/details/105438981
介绍
做 Web 开发,我们经常要和 Servlet Filter,Spring MVC Interceptor 打交道,它们都能对请求进行拦截,那么它们有哪些区别呢?
Servlet Filter
Filter的使用
可能很多小伙伴没怎么用过 Filter,我就简单演示一下
在 web.xml 中配置 2 个 Filter
1
2
3
4
5
6
7
8<filter-mapping>
<filter-name>logFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>imageFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>实现如下,略去了 init 方法和 destroy 方法
1
2
3
4
5
6
7
8@WebFilter(filterName = "logFilter")
public class LogFilter implements Filter {
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
System.out.println("LogFilter execute");
chain.doFilter(request, response);
}
}
1 | @WebFilter(filterName = "imageFilter") |
- 然后你访问任意一个 servlet 方法,LogFilter 和 ImageFilter 的 doFilter 方法都会执行
如果你在一个 Filter 方法后不加c hain.doFilter(request, response)
,则后续的 Filter 和 Servlet 都不会执行,这是为什么呢?看完我手写的 Demo 你一下就明白了
可以看到 Filter 可以在请求到达 Servlet 之前做处理,如
- 请求编码
- 敏感词过滤等
有兴趣的小伙伴可以看看相关的源码
手写Filter的实现
Servlet 接口,任何一个 web 请求都会调用 service 方法
1 | public interface Servlet { |
1 | public class MyServlet implements Servlet { |
拦截器接口
1 | public interface Filter { |
1 | public class LogFilter implements Filter { |
1 | public class ImageFilter implements Filter { |
拦截器链对象
1 | public interface FilterChain { |
1 | public class ApplicationFilterChain implements FilterChain { |
测试例子
1 | public class Main { |
如果任意一个 Filter 方法的最后不加上 chain.doFilter(),则后面的拦截器及 Servlet 都不会执行了。相信你看完 ApplicationFilterChain 类的 doFilter 方法一下就明白了,就是一个简单的递归调用
Spring MVC Interceptor
Interceptor 的使用
今天就来分析一下拦截器是怎么实现的?可以通过以下方式实现拦截器
- 实现HandlerInterceptor接口
- 继承HandlerInterceptorAdapter抽象类,按需重写部分实现即可,(HandlerInterceptorAdapter 也实现了 HandlerInterceptor 接口)
总而言之拦截器必须必须实现了 HandlerInterceptor 接口
HandlerInterceptor 有如下 3 个方法
- boolean preHandler():在 controller 执行之前调用
- void postHandler():controller 执行之后,且页面渲染之前调用
- void afterCompletion():页面渲染之后调用,一般用于资源清理操作
这个图应该很好的显示了一个请求可以被拦截的地方
- Servlet Filter 是对一个请求到达 Servlet 的过程进行拦截
- 而 HandlerInterceptor 是当请求到达 DispatcherServlet 后,在 Controller 的方法执行前后进行拦截
手写 Interceptor 的实现
我来手写一个 Demo,你一下就能明白了
拦截接口,为了方便我这里就只定义了一个方法
1 | public interface HandlerInterceptor { |
定义如下2个拦截器
1 | public class CostInterceptor implements HandlerInterceptor { |
1 | public class LoginInterceptor implements HandlerInterceptor { |
存放拦截器的容器
1 | public class HandlerExecutionChain { |
演示 DispatcherServlet 的调用过程
1 |
|
如果任意一个 Interceptor 返回 false,则后续的 Interceptor 和 Controller 中的方法都不会执行原因在 Demo 中显而易见
当想对请求增加新的过滤逻辑时,只需要定义一个拦截器即可,完全符合开闭原则。
不知道你意识到没有 Servlet Filter 和 Spring MVC Interceptor 都是用责任链模式实现的
来看看 DispatcherServlet 是怎么做的?和我们上面写的 demo 一模一样
我们用 servlet 写 web 应用时,一个请求地址写一个 Servlet 类。
而用了 spring mvc 后,整个应用程序只有一个 Servlet 即 DispatcherServlet,所有的请求都发送到DispatcherServlet,然后通过方法调用的方式执行 controller 的方法
DispatcherServlet 的 doDispatch 方法源码如下,省略了一部分逻辑(所有的请求都会执行这个方法)
1 | protected void doDispatch() { |
Interceptor 可以有如下用处
- 记录接口响应时间
- 判断用户是否登陆
- 权限校验等
总结
- Servlet Filter 和 Spring MVC Interceptor 都能对请求进行拦截,只不过时机不同,Servlet Filter 在请求到达 Servlet 之前拦截,Spring MVC Interceptor 在请求到达 DispatcherServlet 之后拦截
- Servlet Filter 是 Servlet 的规范,而 Spring MVC Interceptor 只能在 Spring MVC 中使用