spring揭秘25-springmvc05-过滤器与拦截器区别(补充)

embedded/2024/10/9 7:25:49/

文章目录

  • 【README】
  • 【1】springmvc拦截器回顾
    • 【1.1】定义与应用
    • 【1.2】拦截器作用范围
  • 【2】servlet过滤器回顾
    • 【2.1】过滤器定义与应用
    • 【2.2】过滤器作用范围
  • 【3】springmvc拦截器与servlet过滤器区别(重要*)
    • 【3.1】拦截方法调用代码实现

【README】

代码详情参见: springmvcDiscoverFirstDemo【github】

1)本文根据spring揭秘25-springmvc03-其他组件(文件上传+拦截器+处理器适配器+异常统一处理) 中的拦截器与过滤器进行总结;

  • 确切的说本文讨论的拦截器指的是springmvc拦截器,过滤器是servlet过滤器;springmvc是基于servlet构建的web框架,但两者有区别;(当然了,servlet有拦截器,也有过滤器)

2)拦截器与过滤器都可以对业务逻辑做拦截,即在上下文织入逻辑,所以把两者放在一起比较;

  • 拦截器与过滤器最重要的应用场景:本文认为是偷梁换柱, 在拦截方法中,用新对象替换已有对象 ; (当然也有其他场景,如日志收集, 参数校验)


springmvc_16">【1】springmvc拦截器回顾

【1.1】定义与应用

1)springmvc拦截器定义:基于servlet拦截器思想,springmvc提供的对servlet内部处理逻辑进行拦截的抽象接口;

2)应用场景:日志收集, 参数校验等; 其实最重要的应用,应该是偷梁换柱;就是在拦截方法中,可以用新对象替换已有对象

【HandlerInterceptor】

java">package org.springframework.web.servlet;import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;import org.springframework.lang.Nullable;
import org.springframework.web.method.HandlerMethod;public interface HandlerInterceptor {default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception {return true;}default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,@Nullable ModelAndView modelAndView) throws Exception {}default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,@Nullable Exception ex) throws Exception {}
}

【TimeCostHandlerInterceptor】自定义拦截器

java">public class TimeCostHandlerInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {request.setAttribute("startTime" , System.currentTimeMillis());return true;}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {Long startTime = (Long) request.getAttribute("startTime");System.out.println(request.getServletPath() + " 执行耗时统计(单位毫秒)=" + (System.currentTimeMillis() - startTime));}
}

【dispatcher-servlet.xml】装配拦截器到HandlerMapping

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:tx="http://www.springframework.org/schema/tx"xmlns:aop="http://www.springframework.org/schema/aop"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsdhttp://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"><!-- 注册自定义处理器拦截器 --><bean id="timeCostHandlerInterceptor"  class="com.tom.springmvc.handlerinterceptor.TimeCostHandlerInterceptor"/><!-- 注册HandllerMapping bean到springweb容器, BeanNameUrlHandlerMapping使用URL与Controller的bean名称进行匹配 --><bean id="beanNameUrlHandlerMapping" class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"><property name="interceptors"><list><ref bean="timeCostHandlerInterceptor" /> <!-- 装配拦截器 --> </list></property></bean><!-- SimpleUrlHandlerMapping: 可以配置web请求到具体二级控制器的映射, 可以把一组或多组拥有相似特征的web请求映射给二级控制器--><bean id="handlerMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"><!-- 设置SimpleUrlHandlerMapping优先级为1,优先匹配,若有多个HandlerMapping时 --><property name="order" value="1" /><property name="mappings"><value>/userController.do=userController/bankCard*.do=bankCardController/bankCard/*.do=bankCardController/pdfUrlView*.do=pdfUrlViewController</value></property></bean></beans>


【1.2】拦截器作用范围

1) 由配置可知,拦截器的作用范围是HandlerMapping ; 如本文配置了2个HandlerMapping,包括 BeanNameUrlHandlerMapping, SimpleUrlHandlerMapping ;而只有BeanNameUrlHandlerMapping装配了timeCostHandlerInterceptor拦截器,而SimpleUrlHandlerMapping 没有;

  • 所以:通过BeanNameUrlHandlerMapping找到的二级处理器,并调用该处理器时,才会有timeCostHandlerInterceptor拦截功能;而SimpleUrlHandlerMapping 没有;
  • 而二级处理器是由一级处理器DispatcherServlet调用HandlerMapping查找到的,所以总结起来,springmvc拦截器是在Servlet内部做拦截;(补充:servlet拦击器是对servlet外部做拦截,即对servlet上下文做拦截) ;


【2】servlet过滤器回顾

【2.1】过滤器定义与应用

1)servlet过滤器:servlet框架提供的对servlet逻辑做前置过滤的抽象接口;

2)应用场景:如参数校验; 与拦截器类似, 其实最重要的应用,应该是偷梁换柱;就是在拦截方法(doFilter)中,可以用新对象替换已有对象

java">package jakarta.servlet;import java.io.IOException;public interface Filter {default public void init(FilterConfig filterConfig) throws ServletException {}public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)throws IOException, ServletException;default public void destroy() {}
}

【CustomFilter】自定义过滤器

java">public class CustomFilter implements Filter {@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {System.out.println(request.getServletContext().getContextPath() + " CustomFilter 过滤器执行");chain.doFilter(request, response);System.out.println(request.getServletContext().getContextPath() + " CustomFilter 过滤器执行完成后");}
}

【web.xml】注册过滤器代理到servlet容器

<!-- 注册过滤器代理 -->
<filter><filter-name>customFilter</filter-name><filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping><filter-name>customFilter</filter-name><url-pattern>/*</url-pattern>
</filter-mapping>

【applicationContext.xml】自定义过滤器注册到spring容器

<!-- 注册自定义过滤器 -->
<bean id="customFilter"  class="com.tom.springmvc.filter.CustomFilter"/>


【2.2】过滤器作用范围

1)过滤器: 对servlet进行拦截,且仅可以做前置拦截(在servlet入口方法执行前拦截); 若满足条件,则调用FilterChain.doFilter()放行;否则封装响应报文,直接返回;



springmvcservlet_207">【3】springmvc拦截器与servlet过滤器区别(重要*)

1)拦截位置不同:

  • 拦截器有3个拦截方法,包括preHandle, postHandle, afterCompletion 方法;可以在上文与下文以及结束时拦截;
  • 过滤器只有1个拦截方法, 包括doFilter方法; 也可以在上下文拦截(FilterChain.doFilter()的上文和下文织入业务逻辑);

2)放行请求的方式不同:

  • 拦截器的preHandle方法通过返回true/false放行请求;
  • 过滤器的doFilter()) 通过调用 FilterChain.doFilter() 放行请求; (责任链模式)

3)作用范围不同:

  • 拦截器是装配给HandlerMapping,是对servlet内部逻辑进行拦截;(本文特指springmvc拦截器)
  • 过滤器是对servlet上文进行拦截,是对servlet外部逻辑进行拦截;(本文特指servlet过滤器)

4)底层拦截机制不同:

  • 拦截器:若有多个拦截器,只要拦截器的preHandle执行通过(返回true,这个非常重要),则其afterCompletion 一定执行(无论是否抛出异常);类似于双向链表;
    • 参考【3.1】HandlerExecutionChain#applyPreHandle()代码, 只有preHandle返回true的拦截器,才会执行其afterCompletion 方法
  • 过滤器:若有多个过滤器,是通过 FilterChain.doFilter() 把请求透传下去,类似于单向链表;


【3.1】拦截方法调用代码实现

【HandlerExecutionChain】 拦截方法调用

java">boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {for (int i = 0; i < this.interceptorList.size(); i++) {HandlerInterceptor interceptor = this.interceptorList.get(i);if (!interceptor.preHandle(request, response, this.handler)) {// 若有一个拦击器前置拦截返回false,则已执行preHandle方法的所有拦截器的afterCompletion方法被执行 【因为暂存了已执行preHandle方法的拦截器索引或下标】 triggerAfterCompletion(request, response, null);return false;}this.interceptorIndex = i; // 暂存已执行preHandle方法的拦截器索引 (下标递增)}return true;
}/*** Apply postHandle methods of registered interceptors.*/
void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv)throws Exception {for (int i = this.interceptorList.size() - 1; i >= 0; i--) {HandlerInterceptor interceptor = this.interceptorList.get(i);interceptor.postHandle(request, response, this.handler, mv);}
}/*** Trigger afterCompletion callbacks on the mapped HandlerInterceptors.* Will just invoke afterCompletion for all interceptors whose preHandle invocation* has successfully completed and returned true.*/
void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex) {// 把已执行preHandle方法的拦截器索引取出,执行其afterCompletion方法(下标递减)for (int i = this.interceptorIndex; i >= 0; i--) { HandlerInterceptor interceptor = this.interceptorList.get(i);try {interceptor.afterCompletion(request, response, this.handler, ex);}catch (Throwable ex2) {logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);}}
}

http://www.ppmy.cn/embedded/124943.html

相关文章

芯课堂 | Synwit_UI_Creator(μgui)平台之图像处理篇

今天小编给大家介绍的是UI_Creator&#xff08;μgui&#xff09;平台下关于图像处理的选项。 UI_Creator&#xff08;μgui&#xff09;平台图片类控件有图像控件和分级图像控件&#xff0c;均包含以下选项&#xff1a; 1、消除水波纹&#xff1a; 由于16位真彩色&#xff08…

微服务——分布式事务

目录 分布式事务 1.1分布式事务的特性 1.2分布式事务应用背景 ​编辑 1.3.认识Seata 1.4部署TC服务 1.4.1.准备数据库表 1.4.2.准备配置文件 1.4.3.Docker部署 1.5.微服务集成Seata 1.5.1.引入依赖 1.5.2.改造配置 1.5.3.添加数据库表 ​编辑1.6.XA模式 1.6.1.两…

【Linux】几种常见配置文件介绍

配置文件目录 linux 系统中有很多配置文件目录 /etc/systemd/system /lib/systemd/system /usr/lib/systemd/system 【结果就是这个目录配置文件是源头】 这三者有什么样的关系呢&#xff1f; 以下是网络上找的资料汇总&#xff0c;并加了一些操作验证。方便后期使用 介…

C++ STL中 set 和 map 的区别

目录 1.引言 2.set 3.map 4.共同点 5.不同点 6.高级用法与注意事项 7.总结 1.引言 在C的标准模板库&#xff08;STL&#xff09;中&#xff0c;set和map是两种常用的容器&#xff0c;它们提供了不同的功能和使用场景。尽管它们底层都基于红黑树实现&#xff0c;有许多相…

Collection 和 Collections 有什么区别?

Collection 和 Collections 在 Java 中是两个截然不同的概念&#xff0c;它们之间的主要区别体现在定义、性质、功能和使用上。 一、定义与性质 Collection 定义&#xff1a;Collection 是 Java 集合框架中的一个根接口&#xff0c;表示一组对象的集合。性质&#xff1a;它是一…

Java入门(基础,常见API,JVM,JUC并发编程)

一.javaSE Java初学者软件安装与idea快捷键-CSDN博客 Java基本概念&#xff08;新手入门&#xff09;_阿伟java资料-CSDN博客 二.常见API JavaAPI-CSDN博客 三.JVM JVM入门-CSDN博客 四.JUC并发编程 JUC并发编程-CSDN博客

【SQL】掌握SQL查询技巧:数据筛选与限制

目录 1. DISTINCT&#xff1a;避免重复记录1.1 示意图1.2 使用场景 2. LIMIT&#xff1a;控制查询结果的数量2.1 示意图2.2 使用场景 3. OFFSET&#xff1a;跳过前几行3.1 示意图3.2 使用场景 4. WHERE子句&#xff1a;精细控制数据过滤4.1 示意图4.2 运算符详细说明4.3 基本条…

边缘端大模型是怎么部署的?重点关注哪些?

写在前面 在设备端运行的大语言模型&#xff08;LLMs&#xff09;&#xff0c;即指在边缘设备上运行LLMs&#xff0c;因其出色的隐私保护、低延迟和节省带宽的特点而引起了广泛关注。然而&#xff0c;与功能更为强大的云中心相比&#xff0c;设备端LLMs的能力本质上受到边缘设…