秒懂SpringBoot之Filter与HandlerInterceptor异同

news2024/9/21 10:36:42

[版权申明] 非商业目的注明出处可自由转载
出自:shusheng007

文章目录

  • 概述
  • 前置知识
  • Filter
    • 原理及使用场景
    • 使用
    • 执行顺序
    • 设置Filter作用范围
  • HandlerInterceptor
    • 原理及使用场景
    • 使用
      • 实现`org.springframework.web.servlet.HandlerInterceptor` 接口
      • 配置
  • 二者异同
    • 共同点
    • 不同点
  • 总结
  • 源码

概述

在日常开发中,我们会经常用到Filter和HandlerInterceptor,刚接触时感觉二者差不多,那二者有什么异同呢?谁先执行谁后执行呢?分别在什么场景下使用呢?接下来让我们看一下

前置知识

先上一张偶亲手画的图吧,正所谓一图胜千言,不理解无所谓,我们一起来看下。
在这里插入图片描述

你有没有觉得在一个熟悉的领域学习相关的新知识就非常容易理解,因为他们直接环环相扣,互相联系,这就是所谓的经验的优势。例如我们今天要谈论的Filter和HandlerIntercetor,如果你不具备Sevlet以及SpringMvc原理的基础知识就会显得很晦涩,而对于有这部分知识的同学就会显得非常的简单易懂。此处我简单描述一下,作为理解下面内容的背景知识。

  1. 利用SpringMvc开发的Web程序需要运行在Servlet容器中(Web服务器),例如Tomcat。
  2. SpringMvc使用一个叫DispatcherServlet的组件来接收所有的请求,然后分发给我们写得Controller。

假设我们使用springboot写了一个helloworld的web程序,使用内置的Tomcat来运行,那么一个请求过来会按照下面的路径处理。

request-->tomcat-->filter-->dispatcherSevlet-->handlerInterceptor-->controller

Filter

原理及使用场景

首先Filter不属于Spring框架,而是属于WebServer的,例如Tomcat,其位于org.apache.tomcat.embed:tomcat-embed-core中。
在这里插入图片描述
因为请求到达servlet之前都要经过Filter,在此我们可以访问Request和Response,因而可以做很多切面性的工作,最典型的就是授权和认证。例如Spring Security就是使用Filter工作的。

使用

在springboot程序中实现一个Filter非常简单,只需要实现javax.servlet.Filter接口并使用@Componse标记即可

@Slf4j
@Component
public class AuthFilter implements Filter {
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        log.info("AuthFilter请求url:{}", request.getRequestURL());

        filterChain.doFilter(servletRequest, servletResponse);
    }
}

doFilter方法中我们可以拿到ServletRequest ServletResponse ,因而可以获取到非常多请求相关的信息,然后根据自己的业务来处理即可

执行顺序

既然有多个Filter,那么就会存在执行顺序问题,我们如何控制多个Filter的执行顺序呢?

可以使用@Order注解

@Slf4j
@Order(1)
@Component
public class AuthFilter implements Filter {
	...
}

order里的数字越小越早执行。

设置Filter作用范围

默认情况下Filter将作用于每个请求,我们可以设置让其只作用于某些特定的请求,例如我我们设置AuthFilter 只作用于/auth开头的请求。在这里也可以设置执行顺序,其优先级高于@Order

@Configuration
public class FilterConfiguration {
    @Autowired
    private AuthFilter authFilter;
    
    @Bean
    public FilterRegistrationBean<AuthFilter> filterRegistrationBean() {
        FilterRegistrationBean<AuthFilter> registrationBean = new FilterRegistrationBean<>();
        registrationBean.setFilter(authFilter);
        registrationBean.addUrlPatterns("/auth/*");
        registrationBean.setOrder(0);
        return registrationBean;
    }
}

通过这种方法还可以使用第三方的Filter。

HandlerInterceptor

原理及使用场景

HandlerInterceptorSpringMvc的组件,其位于DispatcherServletController之间。其位于
org.springframework:spring-webmvc中。

使用

在springboot程序中实现一个HandlerInterceptor较为简单,但是比Filter难一点,需要两步。

实现org.springframework.web.servlet.HandlerInterceptor 接口

其包含3个default方法,我们选择性的实现即可,preHandle使用的频率更高。

  • preHandle:在Controller方法执行之前执行
  • postHandle:在Controller方法执行以后,但是还没有渲染页面之前执行。

这就是它为什么多了一个ModelAndView 类型的参数,但是如今流行前后端分离,所以一般都是返回json数据给前端,不会返回html页面,所以这个参数几乎不怎么用的到。

  • afterCompletion: 在Controller方法完全执行完毕后触发

下面是一个实现。

@Slf4j
public class LogInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        log.info("preHandle {}:{}:{}",request.getRequestURL(),response.getStatus(),handler);
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        log.info("postHandle {}:{}:{}:{}",request,response,handler,modelAndView);
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        log.info("afterCompletion {}:{}:{}:{}",request,response,handler,ex);
    }
}

配置

有了Interceptor还需要使其生效,我们需要实现org.springframework.web.servlet.config.annotation.WebMvcConfigurer 。因为SpringBoot已经默认启用了@EnableWebMvc,所以可以使用这个接口的实现类配置web相关的功能,这个接口的可配置项纷繁复杂,幸好SpringBoot已经帮我们配置了默认值,不然就蛋疼了… 这里我们只需要重写addInterceptors即可

@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LogInterceptor());
    }
}

二者异同

共同点

在SpringMvc中二者均可以实现切面性的工作。

不同点

首先两个东西隶属于不同的框架,Filter更具通用性,粒度更粗。例如你只能从Filter里面拿到http请求相关的信息,而拿不到应用层面的信息,例如你写的那个Controller里面的信息。HandlerInterceptor属于SpringMvc的,它的通用性更差,但是控制粒度更细,因为可以获取到应用层面的信息了。例如我现在想在log中记录类名和方法名,Filter就做不到,但是SpringSecurity这类业务无关框架却又不能使用Interceptor。

总结

总之二者各有各的适用场景,合适的才是最好的。这就跟找对象是一样一样的,合适当前场景的才是最好的,随着时间的流逝情况也许会有变化,到时候重构就好了。

源码

一如既往,你可以在首发文章文末找到源码地址秒懂SpringBoot之弄懂Filter与HandlerInterceptor

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

RocketMQ 高级特性

1&#xff0c;事务消息代码实现 之前我们已经在讨论订单业务消息丢失问题中引出了事务消息&#xff0c;本内容我们就实际用代码来实现一下事务消息吧。 首先我们用原生代码来实现一下事务消息&#xff0c;下面是事务消息生产者TransactionProducer类的代码&#xff0c;具体代码…

基于LinkedList高性能android列表适配器

1、前言 我们大部分的时候都是使用ArrayList作为Android适配器Adapter&#xff08;无论是ListView或者RecyclerView&#xff09;下的数据容器。为什么使用ArrayList呢&#xff1f;因为他的内部是由数组实现的&#xff0c;所以访问数组元素速度最快&#xff0c;但是如果数据变化…

JNI内两种方式从C/C++中传递一维、二维、三维数组数据至Java层详细梳理

目录 0 前言 1 准备工作介绍 2 一维数组 2.1 return形式 2.2 参数形式 3 二维数组 3.1 return形式 3.2 参数形式 4 三维数组 4.1 return形式 4.2 参数形式 5 测试代码 6 结果说明 0 前言 就如之前我写过的一篇文章【JNI内形参从C代码中获取返回值并返回到Java层使…

Elsevier上传LaTeX 修改稿踩坑

背景 千辛万苦修改完论文&#xff0c;结果发现要求上传可编辑文件&#xff0c;tex上传真的太难了&#xff0c;一堆坑&#xff0c;尤其是编译错误&#xff0c;要等系统创建pdf后才能找到。中间还打了北京的客服电话&#xff0c;结果他们那边并不懂相关的东西。说latex是第三方公…

C语言-基础了解-22-C文件读写

C文件读写 一、打开文件 可以使用 fopen( ) 函数来创建一个新的文件或者打开一个已有的文件&#xff0c;这个调用会初始化类型 FILE 的一个对象&#xff0c;类型 FILE 包含了所有用来控制流的必要的信息。下面是这个函数调用的原型&#xff1a; FILE *fopen( const char *fil…

JS中undefined和null的区别

● JavaScript 真是一个特殊的语言, 其他语言都只有一个表示 “无” 的值, 比如 Java 语言用的是 null, C 语言用的是 NULL, Python 语言用的是 None, Ruby 语言用的是 nil. 只有 JS 里面表示 “空” 的有两个, 一个是 undefined, 一个是 null ● 很多小朋友在刚开始学习的时候…

【项目设计】高并发内存池(六)[细节优化+测试]

&#x1f387;C学习历程&#xff1a;入门 博客主页&#xff1a;一起去看日落吗持续分享博主的C学习历程博主的能力有限&#xff0c;出现错误希望大家不吝赐教分享给大家一句我很喜欢的话&#xff1a; 也许你现在做的事情&#xff0c;暂时看不到成果&#xff0c;但不要忘记&…

[ 网络 ] 应用层协议 —— HTTP协议

目录 1.HTTP协议 1.1URL urlencode和urldecode 2. HTTP协议格式 HTTP请求 HTTP响应 3.告知服务器意图的HTTP方法 GET&#xff1a;获取资源 POST&#xff1a;传输实体主体 GET和POST的区别 使用Cookie的状态管理 4.返回结果的HTTP状态码 状态码告知从服务器端返回的…

十连胜!实在智能×浙江省十家农商行,数字科技赋能普惠金融

近日&#xff0c;中共中央、国务院印发了《数字中国建设整体布局规划》&#xff08;以下简称《规划》&#xff09;。《规划》指出&#xff0c;建设数字中国是数字时代推进中国式现代化的重要引擎&#xff0c;是构筑国家竞争新优势的有力支撑。全面提升数字中国建设的整体性、系…

C语言-基础了解-23-C预处理器

C预处理器 一、C预处理器 C 预处理器不是编译器的组成部分&#xff0c;但是它是编译过程中一个单独的步骤。简言之&#xff0c;C 预处理器只不过是一个文本替换工具而已&#xff0c;它们会指示编译器在实际编译之前完成所需的预处理。我们将把 C 预处理器&#xff08;C Prepr…

spring-security2

参考b站up主&#xff1a;传送门 前沿 &#xff1a; 回顾上章&#xff1a;最顶层就是一个过滤器 SpringSecurity流程&#xff1a;FilterChainProxy->根据请求决定一个 SecurityFilterChain (挨个调用其matches方法 匹配请求能否处理)-> 执行SecurityFilterChain中的一系列…

Java简单认识泛型——图文详解

写在开头:想必大家和博主一样&#xff0c;在以往学习JavaSE的语法中&#xff0c;遇到了一个陌生的词——泛型&#xff0c;博主当时很好奇&#xff0c;什么是泛型呢&#xff1f;即使是学完了JavaSE&#xff0c;这个问题都没有解决&#xff0c;只能在百度查阅了解关于泛型的一些皮…

Maven依赖的基本概念

目录 1.依赖的基本配置 2.依赖范围 3.传递性依赖 1.依赖的基本配置 根元素project下的dependencies可以包含多个 dependence元素&#xff0c;以声明多个依赖。每个依赖都应该包含以下元素&#xff1a; 1. groupId, artifactId, version : 依赖的基本坐标&#xff0c; 对于任…

【C和C++】输出100内能够被13整除的数,取模判断方法

目录 前言基础概念重温整除例子小知识点收尾前言 在软件行业已经有快十年,技术虽然一般般,但是足够应付和解决编程入门的相关问题! 都说十年磨一剑,积累到一定经验,是时候发挥自己的价值,给予入门的同行些许的帮助! 为什么要写收费专栏,其实原因很简单,时间就是金钱(…

聚观早报 |拼多多跨境电商业务正式登陆澳洲;中国加快6G网络研发

今日要闻&#xff1a;拼多多跨境电商业务正式登陆澳洲&#xff1b;全球自动驾驶公司排名特斯拉垫底&#xff1b;中国将加快 6G 网络研发&#xff1b;B站再次“崩”上热搜&#xff01;已闪电修复&#xff1b;微软将必应AI聊天每次对话上限增加至8条拼多多跨境电商业务正式登陆澳…

大神教你在 Linux 中查看你的时区

在这篇短文中&#xff0c;我们将向你简单介绍几种 Linux 下查看系统时区的简单方法。在 Linux 机器中&#xff0c;尤其是生产服务器上的时间管理技能&#xff0c;是在系统管理中一个极其重要的方面。Linux 包含多种可用的时间管理工具&#xff0c;比如 date 或 timedatectlcomm…

自动化测试——执行javaScript脚本

文章目录一、点击元素(对应的click())二、input标签对应的值&#xff08;对应的send_keys()&#xff09;修改时间控件的属性值&#xff1a;三、元素的文本属性四、js脚本滚动操作一、点击元素(对应的click()) 使用场景&#xff1a;当使用显性等待不能解决问题时 代码中实现点击…

[神经网络]DETR目标检测网络

一、概述 相较于传统目标检测&#xff0c;DETR是一种纯端到端的网络。它不再需要NMS(非极大值抑制&#xff0c;用于去除多余的预测框)和生成anchor。 DETR提出了一个新的目标函数&#xff08;二分图匹配&#xff09;&#xff0c;这个函数可以强制网络输出一个独一无二的预测值&…

【Unity大气渲染】Unity Shader中实现大气散射(半成品)

写在前面 这是之前在做天空盒的时候同步写的分析博客&#xff0c;结果后面写到一半就忘了继续了&#xff0c;这里先贴出当时写的半成品&#xff0c;有小伙伴问我怎么做的&#xff0c;这里只能尽力把之前的半成品先放出来了&#xff08;写得很乱&#xff0c;勿怪orz&#xff09…

用C语言实现一个任意类型的队列

下面是一个简单的无类型队列的实现&#xff1a; #include <stdio.h> #include <stdlib.h>typedef struct Node {void *data;struct Node *next; } Node;typedef struct Queue {Node *front;Node *rear;int size; } Queue;void enqueue(Queue *queue, void *data);…