【框架篇】过滤器和拦截器的区别以及使用场景

在项目开发中,常常会同时配置拦截器(Interceptor)和过滤器(Filter),以下就是它们两个主要的区别:

过滤器(Filter)

配置和实现

Filter的实现还是很简单的,可以实现对应的Filter接口,也可以通过@WebFilter注解对Url进行拦截,其中主要是有三个方法:

  • init():在容器启动初始化锅炉其的时候被调用,在过滤器的整个生命周期之内进会被调用一次,如果执行失败,过滤器就不会生效
  • doFilter():在容器的每一次请求都会触发这个方法,通过FilterChain来调用下一个过滤器
  • destroy():当容器销毁过滤器的实例的时候调用,一般用于销毁或关闭资源,在整个生命周期中也是只会被调用一次
    @Component
    public class MyFilter implements Filter {@Overridepublic void init(FilterConfig filterConfig) throws ServletException {System.out.println("Filter 前置");}@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {System.out.println("Filter 处理中");filterChain.doFilter(servletRequest, servletResponse);}@Overridepublic void destroy() {System.out.println("Filter 后置");}
    }

拦截器(Interceptor) 

配置和实现

拦截器是链式调用的,一个应用中可以存在多个拦截器,一个请求可以触发的多个拦截器,并且每一个拦截器按照声明的顺序依次执行。主要是通过实现HandlerInterceptor接口,其中主要是有三个方法:

  • preHandler():在请求之前调用。如果返回false,当前请求结束,后续也不会执行
  • postHandler():只有preHandler返回true才会执行,在Controller中的方法调用之后、DispatcherServlet返回渲染视图之前被调用
  • afterCompletion():只有preHandle()方法返回值为true时才会执行,在整个请求结束之后、DispatcherServlet渲染了对应的视图之后执行
    @Component
    public class MyInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {System.out.println("Interceptor 前置");return true;}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {System.out.println("Interceptor 处理中");}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {System.out.println("Interceptor 后置");}
    }

过滤器和拦截器区别

过滤器和拦截器的主要区别有以下几点:

  • 底层实现不同:
    • 过滤器:底层通过函数回调来实现。在自定义过滤器中实现的doFilter()方法有一个FilterChain参数,它是一个回调接口。
    • 拦截器:Java的反射机制(动态代理)。
  • 使用范围
    • 过滤器:依赖Tomcat等容器,仅用于web程序。
    • 拦截器:由Spring容器管理,可用于多种程序。
  • 触发时机(重点):
    • 过滤器:在请求进入到容器后,进入servlet之前进行预处理,请求结束是在servlet处理完以后。
    • 拦截器:拦截器是在servlet之后,进入到Controller之前进行预处理,在Controller中渲染了对应的视图之后请求结束。

  • 注入Bean的的情况不同:
    • 过滤器:在过滤器中注入service是可行的。
    • 拦截器:在拦截器中注入service是不可行的,原因是拦截器的加载是在spring容器初始化之前的,如果如果注入会出现错误。解决方案就是手动注入如下
      @Configuration
      public class MyMvcConfig implements WebMvcConfigurer {//让 Spring 容器能够通过这个方法来获取MyInterceptor实例@Beanpublic MyInterceptor getMyInterceptor(){System.out.println("注入了MyInterceptor");return new MyInterceptor();}@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(getMyInterceptor()).addPathPatterns("/**");}
      }

      使用registry.addInterceptor(getMyInterceptor()).addPathPatterns("/**");来注册拦截器。这里不是直接使用new MyInterceptor(),而是调用getMyInterceptor方法获取实例。这样做的好处是,在获取MyInterceptor实例时,由于getMyInterceptor方法是由 Spring 容器管理的(因为它在@Configuration类中),Spring 会确保在创建MyInterceptor实例时,相关的依赖(如可能需要注入的 Service)已经被正确初始化。

使用场景

一般在项目中,这两个是配合在一起来进行使用的,比如我在项目中实现用户上下文的打通,首先通过过滤器拦截请求,将用户的唯一id存入到请求的body当中,再通过拦截器,从body中获取openid存入到封装的用户上下文对象当中。

//在网关集成过滤器
@Component
@Slf4j
public class LoginFilter implements GlobalFilter {@Override@SneakyThrowspublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {ServerHttpRequest request = exchange.getRequest();ServerHttpResponse response = exchange.getResponse();ServerHttpRequest.Builder mutate = request.mutate();String url = request.getURI().getPath();log.info("LoginFilter.filter.url:{}", url);if (url.equals("/user/doLogin")) {return chain.filter(exchange);}SaTokenInfo tokenInfo = StpUtil.getTokenInfo();log.info("LoginFilter.filter.url:{}", new Gson().toJson(tokenInfo));String loginId = (String) tokenInfo.getLoginId();mutate.header("loginId", loginId);return chain.filter(exchange.mutate().request(mutate.build()).build());}}
public class LoginIntercepter implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {String loginId = request.getHeader("loginId");LoginContextHolder.set("loginId",loginId);return true;}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {LoginContextHolder.remove();}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/437219.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Python语言初识(六)】

一、网络编程入门 1.1、TCP/IP模型 实现网络通信的基础是网络通信协议&#xff0c;这些协议通常是由互联网工程任务组 &#xff08;IETF&#xff09;制定的。所谓“协议”就是通信计算机双方必须共同遵从的一组约定&#xff0c;例如怎样建立连接、怎样互相识别等&#xff0c;…

k8s搭建一主三从的mysql8集群---无坑

一&#xff0c;环境准备 1.1 k8s集群服务器 ip角色系统主机名cpumem192.168.40.129mastercentos7.9k8smaster48192.168.40.130node1centos7.9k8snode148192.168.40.131node2centos7.9k8snode248192.168.40.132node3centos7.9k8snode348 k8s集群操作请参考《K8s安装部署&…

力扣(leetcode)每日一题 1845 座位预约管理系统| treeSet和priority Queue的区别|线段树

之前发过一篇&#xff0c;感觉还有深挖的地方&#xff0c;于是又补充一些信息 这题目虽然是middle难度题目&#xff0c;要解答出来是只要easy的时间&#xff0c;但是深挖可以有hard的难度 题解1 可以帮助复习线段树的使用&#xff0c;题解2 可以复习一下java基础知识 题解1 线…

Springboot使用redis,以及解决redis缓存穿透,击穿,雪崩等问题

1.Redis面试题-缓存穿透,缓存击穿,缓存雪崩 1 穿透: 两边都不存在&#xff08;皇帝的新装&#xff09; &#xff08;返回空值&#xff09;&#xff08;互斥锁&#xff09;&#xff08;黑名单&#xff09; &#xff08;布隆过滤器&#xff09; 2 击穿&#xff1a;一个或多个热…

Kotlin:1.8.0 的新特性

一、概述 Kotlin 1.8.0版本英语官方文档 Kotlin 1.8.0 中文官方文档 The Kotlin 1.8.0 release is out and here are some of its biggest highlights: Kotlin 1.8.0发布了&#xff0c;下面是它的一些亮点: JVM 平台新增实验性函数&#xff1a;递归复制或删除目录内容改进了 …

9--苍穹外卖-SpringBoot项目中Redis的介绍及其使用实例 详解

目录 Redis入门 Redis简介 Redis服务启动与停止 服务启动命令 Redis数据类型 5种常用数据类型介绍 各种数据类型的特点 Redis常用命令 字符串操作命令 哈希操作命令 列表操作命令 集合操作命令 有序集合操作命令 通用命令 在java中操作Redis Redis的Java客户端 …

uni-app在线预览pdf

这里推荐下载pdf.js 插件 PDF.js - Browse Files at SourceForge.net 特此注意 如果报 Promise.withResolvers is not a function 请去查看版本兼容问题 降低pdf.js版本提高node版本 下载完成后 在 static 文件夹下新建 pdf 文件夹&#xff0c;将解压文件放进 pdf 文件…

生信初学者教程(十一):数据校正

文章目录 介绍加载R包导入数据准备数据ComBatremoveBatchEffectVoom SNM批次效应校正结果比较校正后的结果输出校正后的结果总结介绍 批次效应在生物学数据分析中是一个普遍存在的问题,它指的是由于实验过程中非生物学因素(如样本处理时间、实验条件、测序平台等)的差异,导…

集师专属知识付费小程序搭建 心理咨询小程序搭建

一、产品简介 集师SaaS知识付费软件&#xff0c;为知识创业者或商家提供一站式内容交付解决方案&#xff0c;助力商家搭建集品牌传播、商业变现和用户运营于一体的线上知识服务系统&#xff0c;覆盖全渠道经营场景&#xff0c;占据每个流量入口&#xff0c;使流量变现快速高效…

Python笔记 - 利用装饰器设计注解体系

认识注解 注解&#xff08;Annotation&#xff09;是一种用于为代码添加元数据的机制。这些元数据可以在运行时被访问&#xff0c;用于为代码元素&#xff08;如类、方法、字段等&#xff09;提供额外的信息或指示。 由于Python中装饰器只能装饰类和方法&#xff0c;因此也只…

828华为云征文|华为云弹性云服务器FlexusX实例下的Nginx性能测试

本文写的是华为云弹性云服务器FlexusX实例下的Nginx性能测试 目录 一、华为云弹性云服务器FlexusX实例简介二、测试环境三、测试工具四、测试方法五、测试结果 下面是华为云弹性云服务器FlexusX实例下的Nginx性能测试。 一、华为云弹性云服务器FlexusX实例简介 华为云弹性云服…

【LLM论文日更】| 通过指令调整进行零样本稠密检索的无监督文本表示学习

论文&#xff1a;https://arxiv.org/pdf/2409.16497代码&#xff1a;暂未开源机构&#xff1a;Amazon AGI、宾夕法尼亚州立大学领域&#xff1a;Dense Retrieval发表&#xff1a;Accepted at DCAI24 workshopCIKM2024 研究背景 研究问题&#xff1a;这篇文章要解决的问题是如…

泰勒图 ——基于相关性与标准差的多模型评价指标可视化比较-XGBoost、sklearn

1、基于相关性与标准差的多模型评价指标可视化比较 # 数据读取并分割 import pandas as pd import numpy as np import matplotlib.pyplot as plt from sklearn.model_selection import train_test_split plt.rcParams[font.family] = Times New Roman plt.rcParams[axes.unic…

【C++】第一节:C++入门

1、C关键字 2、命名空间 在C/C中&#xff0c;变量、函数和后面要学到的类都是大量存在的&#xff0c;这些变量、函数和类的名称将都存在于全局作用域中&#xff0c;可能会导致很多冲突。使用命名空间的目的是对标识符的名称进行本地化&#xff0c;以避免命名冲突或名字污染&am…

Updates were rejected because the tip of your current branch is behind 的解决方法

1. 问题描述 当我们使用 git push 推送代码出现以下问题时&#xff1a; 2. 原因分析 这个错误提示表明当前本地分支落后于远程分支&#xff0c;因此需要先拉取远程的更改。 3. 解决方法 1、拉取远程更改 在终端中执行以下命令&#xff0c;拉取远程分支的更新并合并到本地…

奔驰EQS450suv升级增强AR抬头显示HUD案例分享

以下是奔驰 EQS450 SUV 升级增强版 AR 抬头显示的一般改装案例步骤及相关信息&#xff1a; 配件&#xff1a;通常包括显示屏、仪表模块、饰板等。 安装步骤&#xff1a; 1. 拆下中控的仪表。 2. 在仪表上预留位置切割出合适的孔位&#xff0c;用于安装显示器。 3. 将显示器…

【JavaEE】——多线程常用类

阿华代码&#xff0c;不是逆风&#xff0c;就是我疯 你们的点赞收藏是我前进最大的动力&#xff01;&#xff01; 希望本文内容能够帮助到你&#xff01;&#xff01; 目录 引入&#xff1a; 一&#xff1a;Callable和FutureTask类 1&#xff1a;对比Runnable 2&#xff1a…

动手学深度学习-GPU常见报错-CUDA11.4-AssertionError: Torch not compiled with CUDA enabled

目录 本文还能解决&#xff1a; 0. 问题原因 1. 查看机器的cuda版本 2. 从官网下载对应的torch和torchvision 3. 具体安装方法 本文还能解决&#xff1a; torch.cuda.is_available() 输出为 False&#xff1b; torch.cuda.device_count() 输出为 0 0. 问题原因 这两个问题…

【C++笔记】初始模版和STL简介

【C笔记】初始模版和STL简介 &#x1f525;个人主页&#xff1a;大白的编程日记 &#x1f525;专栏&#xff1a;C笔记 文章目录 【C笔记】初始模版和STL简介前言一.初始模版1.1泛型编程1.2函数模版1.3类模板 二.STL简介2.1什么是STL2.2STL的版本2.3STL的六大组件2.4STL的重要…