过滤器和拦截器的使用和原理

2024-08-30 03:44

本文主要是介绍过滤器和拦截器的使用和原理,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1. 过滤器和拦截器

过滤器(Filter)
拦截器(Interceptor)
在这里插入图片描述

1.1 区别

过滤器和拦截器触发时机不一样

  • 过滤器是在请求进入容器后,但请求进入servlet之前进行预处理的。
  • 请求结束返回也是,是在servlet处理完后,返回给前端之前

拦截器可以获取IOC容器中的各个bean,而过滤器就不行

  • 因为拦截器是spring提供并管理的,spring的功能可以被拦截器使用,在拦截器里注入一个service,可以调用业务逻辑。
  • 过滤器是JavaEE标准只需依赖servlet api ,不需要依赖spring

过滤器的实现基于回调函数。而拦截器(代理模式)的实现基于反射

Filter依赖于Servlet容器,属于Servlet规范的一部分,而拦截器则是独立存在的,可以在任何情况下使用

Filter的执行由Servlet容器回调完成,而拦截器通常通过动态代理(反射)的方式来执行。

Filter的生命周期由Servlet容器管理,而拦截器则可以通过IoC容器来管理,因此拦截器可以通过注入等方式来获取其他Bean的实例,因此使用会更方便。

最简单明了的区别就是:

  • 过滤器可以修改request,而拦截器不能
  • 过滤器需要在servlet容器中实现,拦截器可以适用于javaEE,javaSE等各种环境
  • 拦截器可以调用IOC容器中的各种依赖,而过滤器不能
  • 过滤器只能在请求的前后使用,而拦截器可以详细到每个方法

本质区别
   从灵活性上说拦截器功能更强大些,Filter能做的事情它都能做,而且可以在请求前,请求后执行,比较灵活。
   Filter主要是针对URL地址做一个编码的事情、过滤掉没用的参数、安全校验,其他的还是建议用interceptor。

1.2 执行顺序

过滤前-----拦截前-----Action处理-----拦截后-----过滤后。

【过滤器】开始执行
【拦截器】处理前
com.boot.filter.controller.HelloController
Controller:Hello World!
【拦截器】处理中
【拦截器】耗时:20ms
【拦截器】处理后
【拦截器】耗时:20ms
【过滤器】耗时:27ms
【过滤器】结束执行

过滤器(Filter) :可以拿到原始的http请求,但是拿不到你请求的控制器和请求控制器中的方法的信息
拦截器(Interceptor):可以拿到你请求的控制器和方法,却拿不到请求方法的参数
切片(Aspect): 可以拿到方法的参数,但是却拿不到http请求和响应的对象
在这里插入图片描述
在这里插入图片描述

2. 过滤器

过滤器是处于客户端与服务器资源文件之间的一道过滤网

在访问资源文件之前,通过一系列的过滤器对请求进行修改、判断等,把不符合规则的请求在中途拦截或修改。也可以对响应进行过滤,拦截或修改响应

两种实现方式
1、使用spring boot提供的FilterRegistrationBean注册Filter
2、使用原生servlet注解定义Filter

两种方式的本质都是一样的,都是去FilterRegistrationBean注册自定义Filter

2.1 Filter

2.1.1 示例

2.1.1.1 自定义一个TimeFilter类
@Component
@WebFilter(urlPatterns = {"/*"})
public class TimeFilter implements Filter{Logger log = LoggerFactory.getLogger(Logger.class);@Overridepublic void init(FilterConfig filterConfig) throws ServletException {log.info("【过滤器】初始化");}@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {log.info("【过滤器】开始执行");Long startTime = System.currentTimeMillis();filterChain.doFilter(servletRequest, servletResponse);log.info("【过滤器】耗时:" + (System.currentTimeMillis() - startTime)+"ms");log.info("【过滤器】结束执行");}@Overridepublic void destroy() {log.info("【过滤器】销毁");}
}
2.1.1.2 配置方式
  • @WebFilter注解的urlPatterns属性配置了哪些请求可以进入该过滤器,/*表示所有请求
  • 除了在过滤器类上加注解外,我们也可以通过FilterRegistrationBean来注册过滤器。定义一个TimeFilterConfig类,加上@Configuration注解表明其为配置类,然后通过FilterRegistrationBean来注册过滤器。
    @Configuration
    public class TimeFilterConfig {@Beanpublic FilterRegistrationBean timeFilter() {FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();TimeFilter timeFilter = new TimeFilter();filterRegistrationBean.setFilter(timeFilter);List<String> urlList = new ArrayList<>();urlList.add("/*");filterRegistrationBean.setUrlPatterns(urlList);return filterRegistrationBean;}
    }
    
2.1.1.3 测试
@RestController
public class HelloController {Logger log = LoggerFactory.getLogger(Logger.class);@RequestMapping("hello")public void hello(){log.info("Controller:Hello World!");}
}

运行结果:

【过滤器】开始执行
ControllerHello World!
【过滤器】耗时:26ms
【过滤器】结束执行

2.2 OncePerRequestFilter

2.2.1 概念

在Spring中,Filter默认继承OncePerRequestFilter

Filter 可以在 Servlet 执行之前或之后调用。当请求被调度给一个 Servlet 时,RequestDispatcher 可能会将其转发给另一个 Servlet。另一个 Servlet 也有可能使用相同的 Filter。在这种情况下,同一个 Filter 会被调用多次。

OncePerRequestFilter是 Spring 框架中的一个抽象类,

  • 用于确保在每个请求中只执行一次过滤操作
  • 它通常用于实现一些需要在每个请求中执行一次的逻辑

    比如日志记录、身份验证等

可以继承 OncePerRequestFilter。

Spring 保证 OncePerRequestFilter 只对指定请求执行一次

2.2.1.1 一般只会请求一次,那为什么还要使用该注解

此方法是**为了兼容不同的web container**,也就是说并不是所有的container都是我们期望的只过滤一次,servlet版本不同,执行过程也不同

  • servlet2.3中Filter会经过一切请求,包括服务器内部使用的forward转发请求<%@ include file=”/login.jsp”%>的情况
  • servlet2.4中Filter默认情况下只过滤外部提交的请求forward和include这些内部转发都不会被过滤
  • 所以,若是在Spring环境下使用Filter的话,还是继承OncePerRequestFilter吧,而不是直接实现Filter接口

2.2.2 OncePerRequestFilter源码解读

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//package org.springframework.web.filter;import java.io.IOException;
import javax.servlet.DispatcherType;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.context.request.async.WebAsyncUtils;public abstract class OncePerRequestFilter extends GenericFilterBean {// 常量,表示已经过滤的请求属性后缀public static final String ALREADY_FILTERED_SUFFIX = ".FILTERED";// 构造函数public OncePerRequestFilter() {}// 核心过滤方法,确保每个请求只执行一次过滤操作public final void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws ServletException, IOException {// 检查请求和响应是否为 HTTP 类型if (request instanceof HttpServletRequest && response instanceof HttpServletResponse) {HttpServletRequest httpRequest = (HttpServletRequest) request;HttpServletResponse httpResponse = (HttpServletResponse) response;// 获取已经过滤的请求属性名称String alreadyFilteredAttributeName = this.getAlreadyFilteredAttributeName();// 检查请求是否已经被过滤boolean hasAlreadyFilteredAttribute = request.getAttribute(alreadyFilteredAttributeName) != null;// 检查是否需要跳过过滤if (!this.skipDispatch(httpRequest) && !this.shouldNotFilter(httpRequest)) {if (hasAlreadyFilteredAttribute) {// 如果是错误调度类型,执行嵌套错误调度过滤if (DispatcherType.ERROR.equals(request.getDispatcherType())) 

这篇关于过滤器和拦截器的使用和原理的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1119699

相关文章

mysql8.0.43使用InnoDB Cluster配置主从复制

《mysql8.0.43使用InnoDBCluster配置主从复制》本文主要介绍了mysql8.0.43使用InnoDBCluster配置主从复制,文中通过示例代码介绍的非常详细,对大家的学习或者... 目录1、配置Hosts解析(所有服务器都要执行)2、安装mysql shell(所有服务器都要执行)3、

Redis中的AOF原理及分析

《Redis中的AOF原理及分析》Redis的AOF通过记录所有写操作命令实现持久化,支持always/everysec/no三种同步策略,重写机制优化文件体积,与RDB结合可平衡数据安全与恢复效率... 目录开篇:从日记本到AOF一、AOF的基本执行流程1. 命令执行与记录2. AOF重写机制二、AOF的

Vue3视频播放组件 vue3-video-play使用方式

《Vue3视频播放组件vue3-video-play使用方式》vue3-video-play是Vue3的视频播放组件,基于原生video标签开发,支持MP4和HLS流,提供全局/局部引入方式,可监听... 目录一、安装二、全局引入三、局部引入四、基本使用五、事件监听六、播放 HLS 流七、更多功能总结在 v

SpringBoot中ResponseEntity的使用方法举例详解

《SpringBoot中ResponseEntity的使用方法举例详解》ResponseEntity是Spring的一个用于表示HTTP响应的全功能对象,它可以包含响应的状态码、头信息及响应体内容,下... 目录一、ResponseEntity概述基本特点:二、ResponseEntity的基本用法1. 创

使用Java填充Word模板的操作指南

《使用Java填充Word模板的操作指南》本文介绍了Java填充Word模板的实现方法,包括文本、列表和复选框的填充,首先通过Word域功能设置模板变量,然后使用poi-tl、aspose-words... 目录前言一、设置word模板普通字段列表字段复选框二、代码1. 引入POM2. 模板放入项目3.代码

使用EasyPoi快速导出Word文档功能的实现步骤

《使用EasyPoi快速导出Word文档功能的实现步骤》EasyPoi是一个基于ApachePOI的开源Java工具库,旨在简化Excel和Word文档的操作,本文将详细介绍如何使用EasyPoi快速... 目录一、准备工作1、引入依赖二、准备好一个word模版文件三、编写导出方法的工具类四、在Export

Python爬虫HTTPS使用requests,httpx,aiohttp实战中的证书异步等问题

《Python爬虫HTTPS使用requests,httpx,aiohttp实战中的证书异步等问题》在爬虫工程里,“HTTPS”是绕不开的话题,HTTPS为传输加密提供保护,同时也给爬虫带来证书校验、... 目录一、核心问题与优先级检查(先问三件事)二、基础示例:requests 与证书处理三、高并发选型:

java程序远程debug原理与配置全过程

《java程序远程debug原理与配置全过程》文章介绍了Java远程调试的JPDA体系,包含JVMTI监控JVM、JDWP传输调试命令、JDI提供调试接口,通过-Xdebug、-Xrunjdwp参数配... 目录背景组成模块间联系IBM对三个模块的详细介绍编程使用总结背景日常工作中,每个程序员都会遇到bu

MySQL之搜索引擎使用解读

《MySQL之搜索引擎使用解读》MySQL存储引擎是数据存储和管理的核心组件,不同引擎(如InnoDB、MyISAM)采用不同机制,InnoDB支持事务与行锁,适合高并发场景;MyISAM不支持事务,... 目录mysql的存储引擎是什么MySQL存储引擎的功能MySQL的存储引擎的分类查看存储引擎1.命令

Python中isinstance()函数原理解释及详细用法示例

《Python中isinstance()函数原理解释及详细用法示例》isinstance()是Python内置的一个非常有用的函数,用于检查一个对象是否属于指定的类型或类型元组中的某一个类型,它是Py... 目录python中isinstance()函数原理解释及详细用法指南一、isinstance()函数