过滤器、监听器、拦截器的区别
前言
过滤器、监听器和拦截器是三种不同概念,也各有各的使用场景,如果刚刚接触这些概念或者没有很好了解这三者的核心的话,很容易会对这些概念混淆,不清楚在什么场景下使用哪些工具。如果你对过滤器、监听器和拦截器三者间尚未有一个比较清晰的认知,不妨看看这篇文章。
过滤器是什么?
过滤器定义在 javax.servlet包,是Servlet规范的一部分,在JavaWeb项目中都可以使用。
我们常常使用过滤器来过滤掉一些无效的请求,避免过多无效请求落到servlet、controller上,导致浪费系统的资源。也常用来对请求的编码进行统一的设置,如配置CharacterEncodingFilter作为字符编码过滤器。同时,过滤器Filter是随你的web应用启动而启动的,只初始化一次,以后就可以拦截相关的请求,只有当你的web应用停止或重新部署的时候才能销毁。
自定义过滤器的步骤也比较简单,只需要实现Filter接口,根据实际需要实现三个父类的方法即可。
package com.xiaoming.util;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
@Component
@Order(1)
@WebFilter(urlPatterns = "/user/*",filterName = "filter1")
public class MyFilter1 implements Filter {
// 在Filter初始化的时候调用
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("MyFilter1 has been initialized ...");
}
/** 每个用户请求都会调用到这个方法,校验通过则doFilter放行到下一个过滤器
* 等到请求通过所有过滤链上的校验后,才能到达servlet
* @param servletRequest
* @param servletResponse
* @param filterChain
* @throws IOException
* @throws ServletException
*/
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("doFilter1开始执行,对"+((HttpServletRequest)servletRequest).getRequestURL().toString()+" 进行过滤 ");
System.out.println("检验接口是否被调用,尝试获取contentType如下: " + servletResponse.getContentType());
filterChain.doFilter(servletRequest,servletResponse);
System.out.println("检验接口是否被调用,尝试获取contentType如下: " + servletResponse.getContentType());
System.out.println("doFilter1执行结束");
}
// Filter对象被销毁的时候调用,注意,执行该方法后会在调用一次dofilter
public void destroy() {
System.out.println("MyFilter1 has been destroyed...");
}
}
更多详细的介绍,可以看我写的这篇关于过滤器的文章:https://www.jianshu.com/p/87a40467e84c
监听器是什么?
监听器Listener也是Servlet规范的一部分,它是实现了javax.servlet.ServletContextListener接口的服务器端程序,它也是随web应用的启动而启动,只初始化一次,随web应用的停止而销毁。它能感知到包括request(请求域),session(会话域)和applicaiton(应用程序)的初始化和属性的变化
主要作用是:做一些初始化的内容添加工作、设置一些基本的内容、比如一些参数或者是一些固定的对象等等。
ps:其实现在开发已经很少有直接用到监听器去做什么功能了,像统计网站在线人数的话,有reids这些更加合适的中间件来实现,很多时候只是采用监听器来完成项目的一些初始化工作。
拦截器是什么?
拦截器和前面的两者不同,拦截器是 AOP 的一种实现策略,用于在某个方法或字段被访问前对它进行拦截,然后在其之前或之后加上某些操作。拦截器不是在web.xml配置的,比如struts在struts.xml配置,在springMVC在spring与springMVC整合的配置文件中配置。
package com.xiaoming.util;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class MyInterceptor implements HandlerInterceptor {
/**
* 对接收到的请求进行前置处理,如果返回true才将请求放行给controller
* 如果返回false,执行中断请求
* @param request
* @param response
* @param handler
* @return
* @throws Exception
*/
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("preHandle has done...");
return true;
}
/**
* 执行croller后,渲染视图之前调用
* @param request
* @param response
* @param handler
* @param modelAndView
* @throws Exception
*/
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("postHandle has done...");
}
/*
整个请求结束后执行
*/
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("afterCompletion has done...");
}
}
更多介绍可以看我写的关于拦截器的文章:https://www.jianshu.com/p/ec6e15fcb0c9
拦截器和过滤器的功能有些相似,都是对客户端的请求按照一定的规则进行拦截,但是两者在具体的应用上还是有比较大的差异的。
比如拦截的颗粒度,过滤器只是可以在请求到达servlet之前和结束servlet之后,做一些逻辑操作,但是拦截器的细化程度可以到具体的某一个方法,甚至是某一个字段。
再比如应用的范围,过滤器是Servlet规范的一部分,所以只要是Web项目,那么就可以使用过滤器。但是 Interceptor 依赖于框架容器,需要引入spring框架才可以使用。
那么,像用户登录校验,使用过滤器和拦截器都可以实现,那我应该怎么区别在什么时候选择哪些应用呢?
在这里我想引用一篇文章的比喻,把整个项目的流程比作一条河,那么监听器的作用就是能够听到河流里的所有声音,过滤器就是能够过滤出其中的鱼,而拦截器则是拦截其中的部分鱼,并且作标记。所以当需要监听到项目中的一些信息,并且不需要对流程做更改时,用监听器;当需要过滤掉其中的部分信息,只留一部分时,就用过滤器;当需要对其流程进行更改,做相关的记录时用拦截器
。
监听器更好的应用是用于信息的监听
过滤器更好的应用是用于做请求的过滤,拦截无效的请求和信息
拦截器则是可以根据实际场景需要,对业务逻辑进行校验和调整。所以类似用户登录校验,拦截器会是更好的选择
参考文章:
https://zhuanlan.zhihu.com/p/69060111
https://zhuanlan.zhihu.com/p/161740475