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

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

相关文章

vue使用docxtemplater导出word

《vue使用docxtemplater导出word》docxtemplater是一种邮件合并工具,以编程方式使用并处理条件、循环,并且可以扩展以插入任何内容,下面我们来看看如何使用docxtempl... 目录docxtemplatervue使用docxtemplater导出word安装常用语法 封装导出方

Linux换行符的使用方法详解

《Linux换行符的使用方法详解》本文介绍了Linux中常用的换行符LF及其在文件中的表示,展示了如何使用sed命令替换换行符,并列举了与换行符处理相关的Linux命令,通过代码讲解的非常详细,需要的... 目录简介检测文件中的换行符使用 cat -A 查看换行符使用 od -c 检查字符换行符格式转换将

Java编译生成多个.class文件的原理和作用

《Java编译生成多个.class文件的原理和作用》作为一名经验丰富的开发者,在Java项目中执行编译后,可能会发现一个.java源文件有时会产生多个.class文件,从技术实现层面详细剖析这一现象... 目录一、内部类机制与.class文件生成成员内部类(常规内部类)局部内部类(方法内部类)匿名内部类二、

使用Jackson进行JSON生成与解析的新手指南

《使用Jackson进行JSON生成与解析的新手指南》这篇文章主要为大家详细介绍了如何使用Jackson进行JSON生成与解析处理,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1. 核心依赖2. 基础用法2.1 对象转 jsON(序列化)2.2 JSON 转对象(反序列化)3.

使用Python实现快速搭建本地HTTP服务器

《使用Python实现快速搭建本地HTTP服务器》:本文主要介绍如何使用Python快速搭建本地HTTP服务器,轻松实现一键HTTP文件共享,同时结合二维码技术,让访问更简单,感兴趣的小伙伴可以了... 目录1. 概述2. 快速搭建 HTTP 文件共享服务2.1 核心思路2.2 代码实现2.3 代码解读3.

Elasticsearch 在 Java 中的使用教程

《Elasticsearch在Java中的使用教程》Elasticsearch是一个分布式搜索和分析引擎,基于ApacheLucene构建,能够实现实时数据的存储、搜索、和分析,它广泛应用于全文... 目录1. Elasticsearch 简介2. 环境准备2.1 安装 Elasticsearch2.2 J

使用C#代码在PDF文档中添加、删除和替换图片

《使用C#代码在PDF文档中添加、删除和替换图片》在当今数字化文档处理场景中,动态操作PDF文档中的图像已成为企业级应用开发的核心需求之一,本文将介绍如何在.NET平台使用C#代码在PDF文档中添加、... 目录引言用C#添加图片到PDF文档用C#删除PDF文档中的图片用C#替换PDF文档中的图片引言在当

Java中List的contains()方法的使用小结

《Java中List的contains()方法的使用小结》List的contains()方法用于检查列表中是否包含指定的元素,借助equals()方法进行判断,下面就来介绍Java中List的c... 目录详细展开1. 方法签名2. 工作原理3. 使用示例4. 注意事项总结结论:List 的 contain

C#使用SQLite进行大数据量高效处理的代码示例

《C#使用SQLite进行大数据量高效处理的代码示例》在软件开发中,高效处理大数据量是一个常见且具有挑战性的任务,SQLite因其零配置、嵌入式、跨平台的特性,成为许多开发者的首选数据库,本文将深入探... 目录前言准备工作数据实体核心技术批量插入:从乌龟到猎豹的蜕变分页查询:加载百万数据异步处理:拒绝界面

Android中Dialog的使用详解

《Android中Dialog的使用详解》Dialog(对话框)是Android中常用的UI组件,用于临时显示重要信息或获取用户输入,本文给大家介绍Android中Dialog的使用,感兴趣的朋友一起... 目录android中Dialog的使用详解1. 基本Dialog类型1.1 AlertDialog(