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

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

相关文章

python中的flask_sqlalchemy的使用及示例详解

《python中的flask_sqlalchemy的使用及示例详解》文章主要介绍了在使用SQLAlchemy创建模型实例时,通过元类动态创建实例的方式,并说明了如何在实例化时执行__init__方法,... 目录@orm.reconstructorSQLAlchemy的回滚关联其他模型数据库基本操作将数据添

Spring配置扩展之JavaConfig的使用小结

《Spring配置扩展之JavaConfig的使用小结》JavaConfig是Spring框架中基于纯Java代码的配置方式,用于替代传统的XML配置,通过注解(如@Bean)定义Spring容器的组... 目录JavaConfig 的概念什么是JavaConfig?为什么使用 JavaConfig?Jav

Spring Boot Interceptor的原理、配置、顺序控制及与Filter的关键区别对比分析

《SpringBootInterceptor的原理、配置、顺序控制及与Filter的关键区别对比分析》本文主要介绍了SpringBoot中的拦截器(Interceptor)及其与过滤器(Filt... 目录前言一、核心功能二、拦截器的实现2.1 定义自定义拦截器2.2 注册拦截器三、多拦截器的执行顺序四、过

Java使用Spire.Doc for Java实现Word自动化插入图片

《Java使用Spire.DocforJava实现Word自动化插入图片》在日常工作中,Word文档是不可或缺的工具,而图片作为信息传达的重要载体,其在文档中的插入与布局显得尤为关键,下面我们就来... 目录1. Spire.Doc for Java库介绍与安装2. 使用特定的环绕方式插入图片3. 在指定位

Springboot3 ResponseEntity 完全使用案例

《Springboot3ResponseEntity完全使用案例》ResponseEntity是SpringBoot中控制HTTP响应的核心工具——它能让你精准定义响应状态码、响应头、响应体,相比... 目录Spring Boot 3 ResponseEntity 完全使用教程前置准备1. 项目基础依赖(M

Java使用Spire.Barcode for Java实现条形码生成与识别

《Java使用Spire.BarcodeforJava实现条形码生成与识别》在现代商业和技术领域,条形码无处不在,本教程将引导您深入了解如何在您的Java项目中利用Spire.Barcodefor... 目录1. Spire.Barcode for Java 简介与环境配置2. 使用 Spire.Barco

Android使用java实现网络连通性检查详解

《Android使用java实现网络连通性检查详解》这篇文章主要为大家详细介绍了Android使用java实现网络连通性检查的相关知识,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录NetCheck.Java(可直接拷贝)使用示例(Activity/Fragment 内)权限要求

C# 预处理指令(# 指令)的具体使用

《C#预处理指令(#指令)的具体使用》本文主要介绍了C#预处理指令(#指令)的具体使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学... 目录1、预处理指令的本质2、条件编译指令2.1 #define 和 #undef2.2 #if, #el

C#中Trace.Assert的使用小结

《C#中Trace.Assert的使用小结》Trace.Assert是.NET中的运行时断言检查工具,用于验证代码中的关键条件,下面就来详细的介绍一下Trace.Assert的使用,具有一定的参考价值... 目录1、 什么是 Trace.Assert?1.1 最简单的比喻1.2 基本语法2、⚡ 工作原理3

C# IPAddress 和 IPEndPoint 类的使用小结

《C#IPAddress和IPEndPoint类的使用小结》本文主要介绍了C#IPAddress和IPEndPoint类的使用小结,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定... 目录一、核心作用网络编程基础类二、IPAddress 类详解三种初始化方式1. byte 数组初始化2. l