一、前言
一直想着写一篇关于过滤器和拦截器
,记得之前面试,面试官突然问了一个谈谈过滤器和拦截器的区别。
当时脑瓜子嗡嗡的,这个没准备过,咋办,支支吾吾的说了先到过滤器在到拦截器。
直接被说,你连请求来了经历那些都不知道,怎么能行呢?
虽然这个是八股文,但是还是比较有内容的,在项目中会使用到,在鉴权、日志记录等!
从此之后,面试前第一件事,就是把过滤器和拦截器看一遍。
今天好好总结一下,不需要在看别人写的了!
不能为了面试而学习,咱们是为了掌握好他们,咱们今天从概念--->场景--->实战--->面试题。
一步步层层递进,不让大家白白点开,一定是有所收获!
执行顺序总体图:
二、过滤器
1、概念
过滤器是一种在 Java Web 应用中用于处理请求和响应的组件。它可以拦截客户端发起的请求,也可以拦截服务器返回的响应,对它们进行处理或者修改。
过滤器属于Servlet规范的一部分,过滤器是用于执行过滤任务的对象,它可以在请求到达 Servlet 之前或响应发送给客户端之前执行一些额外的逻辑。
2、应用场景
日志记录: 过滤器常用于记录请求和响应的日志,包括请求的路径、参数、处理时间等信息。
身份验证和授权: 过滤器可以用于实现身份验证和授权逻辑,例如检查用户是否已登录,是否具有足够的权限访问某个资源。
防御性编程: 过滤器可以用于对请求进行安全检查,防止潜在的攻击,比如阻止恶意请求、XSS(跨站脚本攻击)等。
性能监控: 过滤器可以用于收集请求的处理时间、资源使用等信息,用于性能监控和优化。
3、核心方法
先说一下过滤器的三个核心方法:init 方法:在过滤器被创建并添加到容器时调用,在过滤器的生命周期中只被调用一次。doFilter 方法:是过滤器的核心方法,用于处理请求和响应。可以进行前置处理、请求转发或链的调用,以及后置处理。(FilterChain.doFilter)destroy 方法:在过滤器被销毁前调用,用于进行资源释放和清理工作。在过滤器的生命周期中只被调用一次。
4、实战
编写自己的过滤器配置类: 会把web开头的请求率先通过我们定义的过滤器,我们可以在里面进行权限的校验、记录日志等。
多个过滤器,需要有执行顺序可以使用Spring注解@Order,也可以使用@WebFilter(urlPatterns="/web/order/"),通过请求去到下一个符合条件的过滤器!
咱们使用的注解,需要在启动类加上扫描,不然过滤器是不会生效的!
@ServletComponentScan。
/**
* @author wangzhenjun
* @date 2023/11/22 15:34
*/
@Slf4j
@WebFilter("/web/*")
public class MyFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
Filter.super.init(filterConfig);
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
log.info("用户已经认证,继续处理");
log.info("用户有权限,继续处理");
chain.doFilter(request, response);
log.info("处理完成,放行之后");
}
@Override
public void destroy() {
Filter.super.destroy();
}
}
测试访问,经过了过滤器,来到我们的Controller,最后重新会到过滤器内的doFilter方法!
三、拦截器
1、概念
拦截器(Interceptor)是一种在应用程序处理请求和响应的过程中,插入自定义处理逻辑的组件。拦截器是一种常见的设计模式,它允许在核心处理逻辑之前或之后执行额外的操作。
一般出现在Spring MVC中,Spring MVC 中的拦截器实现原理主要基于 Spring 框架的 AOP和 HandlerInterceptor 接口。
2、应用场景
敏感字检测:过滤器可以用于检测请求中的文本内容,包括表单提交、请求参数等,以查找是否包含敏感字。异常处理: 拦截器可以用于捕获和处理在请求处理过程中发生的异常。这使得开发者可以集中处理异常情况,返回合适的错误响应或记录异常信息。日志记录: 拦截器可用于记录请求和响应的日志信息,包括请求参数、响应状态码、执行时间等。国际化和本地化: 拦截器可以用于根据请求的语言或地区设置合适的国际化或本地化信息,以提供多语言支持。
其实过滤器和拦截器很多场景他们两个都能实现。待会我们说一下区别在那里,都能实现一般采用什么方式去实现!
3、核心方法
先说一下拦截器接口的三个核心方法:
preHandle 方法: 在请求被处理之前调用。该方法在整个请求处理过程中是第一个被调用的方法。
如果该方法返回 true,则请求继续进行后续的处理;如果返回 false,则中断请求处理,不会进入控制器方法。
postHandle 方法: 在请求处理后、视图渲染前调用。在这个方法中,可以进行一些后置处理,如对ModelAndView的修改等。
afterCompletion方法: 在整个请求完成后调用,即在视图渲染完毕或在处理过程中发生异常后调用。这个方法在请求完成后,不论请求处理过程中是否发生异常都会被调用。
4、实战
先创建自己的拦截器类:MyInterceptor、
/**
* @author wangzhenjun
* @date 2023/11/23 9:17
*/
@Slf4j
@Component
public class MyInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
log.info("===>拦截器<===:开始对数据进行敏感字过滤");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) {
// 在请求处理后、视图渲染前执行的逻辑
log.info("===>拦截器<===:我可以改变一下modelAndView!");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
Exception ex) {
log.info("===>拦截器<===:释放资源");
}
}
把自己的拦截器注册上:
/**
* @author wangzhenjun
* @date 2023/11/23 10:54
*/
@Configuration
public class MyWebConfig implements WebMvcConfigurer {
@Autowired
private MyInterceptor myInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(myInterceptor)
.addPathPatterns("/web/*");
}
}
测试访问一下,拦截成功,走了我们自定义的拦截器!
四、面试题:二者有什么区别?
我们从下面几种情况来说一下二者的区别!
1、出身不同
过滤器: 是基于 Java Servlet 规范的一部分,属于 Servlet 容器的一项功能。
拦截器: 是 Spring MVC 框架的一部分,属于 Spring 框架的一项特性。
2、应用场景不同
过滤器: 主要用于全局范围的请求和响应处理,可以对所有请求进行通用性的处理,例如性能监控、身份验证、日志记录等。
拦截器: 主要用于对控制器方法的请求和响应进行处理,拦截器的配置更加灵活,拦截器更接近业务系统,可以实现特定业务逻辑的拦截,例如敏感字检测、异常监控等。
我们把握住侧重点核心是在:
过滤器:通用性功能拦截器:业务逻辑方面。
3、实现原理不同
过滤器的底层实现原理是基于方法回调实现的,我们在doFilter方法中看到chain.doFilter(request, response);,这个就是核心,我们看一下他的源码:
/**
* FilterChain 是 servlet 容器提供给开发人员的一个对象,用于查看已过滤资源请求的调用链。
* 筛选器使用 FilterChain 调用链中的下一个筛选器,或者如果调用筛选器是链中的最后一个筛选器,则调用链末尾的资源。
*/
public interface FilterChain {
/**
* 导致调用链中的下一个筛选器,或者如果调用筛选器是链中的最后一个筛选器,
* 则会导致调用链末尾的资源。
*/
public void doFilter(ServletRequest request, ServletResponse response)
throws IOException, ServletException;
}
拦截器的底层实现原理基于动态代理(HandlerInterceptor 的代理对象是通过AOP机制实现的)和反射机制实现的。
过滤器链HandlerExecutionChain类,有兴趣的可以看一下!
4、执行顺序
我们刚刚就在实战中看到了执行顺序:
我们在看一下代码中的执行顺序,先执行过滤器,在执行拦截器,最后才会进入真正的要调用的方法。
五、总结
看到这里都是成功人士,对于一个面试题,我们不能只背一下,而是从多方面去了解它,这样才能印象深刻。
况且,过滤器和拦截器在企业级应用中还是很常见的,特别是拦截器,谁能说自己的项目里没有使用!
过滤器侧重通用性,拦截器侧重业务,更加灵活!
当然有些东西,使用AOP,自己定义个注解,来进行切面,做一下日志记录,监控啥的也是挺好的。
大家根据自己的场景来选择。