当前位置: 首页 > news >正文

八股文小记 Servlet 过滤器-Spring MVC 拦截器-Spring AOP 拦截器区别

您对执行机制的洞察非常准确!让我们深入分析这三种组件的调用机制及其与 AOP 节点的关系:

一、执行机制的本质区别

组件调用机制实现原理
Servlet 过滤器递归调用通过 FilterChain.doFilter() 显式递归调用下一个节点
Spring MVC 拦截器遍历调用HandlerExecutionChain 内部维护列表,顺序遍历执行
Spring AOP 拦截器链式递归调用通过 MethodInvocation.proceed() 递归调用下一个拦截器,目标方法作为终点节点

二、详细机制解析

1. Servlet 过滤器:显式递归调用

源码调用,通过递归调用

public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException {if (Globals.IS_SECURITY_ENABLED) {ServletRequest req = request;ServletResponse res = response;try {AccessController.doPrivileged(() -> {this.internalDoFilter(req, res); //调用过滤器链return null;});} catch (PrivilegedActionException var7) {Exception e = var7.getException();if (e instanceof ServletException) {throw (ServletException)e;}if (e instanceof IOException) {throw (IOException)e;}if (e instanceof RuntimeException) {throw (RuntimeException)e;}throw new ServletException(e.getMessage(), e);}} else {this.internalDoFilter(request, response);}}private void internalDoFilter(ServletRequest request, ServletResponse response)throws IOException, ServletException {// 1. 还有过滤器就继续执行if (pos < n) {ApplicationFilterConfig filterConfig = filters[pos++];Filter filter = filterConfig.getFilter();filter.doFilter(request, response, this);  // 把 this(链本身)传回去,提供给后续过滤器使用,每次调用就会到这个过滤器链。return;}// 2. 没有过滤器了——终点:调 Servletservlet.service(request, response);
}
public class MyFilter implements Filter {public void doFilter(ServletRequest request, ServletResponse response,FilterChain chain) throws IOException, ServletException {// 前置处理 (递归入口)System.out.println("Filter前处理");// ▶ 显式递归调用:必须手动触发下一个节点 ◀chain.doFilter(request, response);// 后置处理 (递归返回)System.out.println("Filter后处理");}
}

调用栈示例

chain.doFilter
chain.doFilter
chain.doFilter
后处理
后处理
返回
Servlet.service
2. MVC 拦截器:隐式遍历调用

源码调用所有拦截器

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) {HandlerExecutionChain mappedHandler = getHandler(request); // 获取执行链// 1. 前置拦截if (!mappedHandler.applyPreHandle(request, response)) return; // 2. 执行业务ControllerModelAndView mv = ha.handle(processedRequest, response, mappedHandler.getHandler());// 3. 后置拦截mappedHandler.applyPostHandle(request, response, mv);// 4. 渲染视图后触发afterCompletionmappedHandler.triggerAfterCompletion(request, response, null);
}
public class HandlerExecutionChain {private final List<HandlerInterceptor> interceptors = new ArrayList<>();boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) {// ▶ 顺序遍历执行 preHandle ◀for (int i = 0; i < this.interceptors.size(); i++) {if (!interceptors.get(i).preHandle(request, response, this.handler)) {return false; // 中断}}return true;}void applyPostHandle(HttpServletRequest request, HttpServletResponse response, ModelAndView mv) throws Exception {// ▶ 逆序遍历执行 postHandle ◀for (int i = this.interceptors.size() - 1; i >= 0; i--) {interceptors.get(i).postHandle(request, response, this.handler, mv);}}
}
AOP增强,本质上也是拦截器MethodInterceptor
一、核心矛盾解析:为什么最后一个节点直接调用业务方法?

源码调用,每次调用将该拦截器链传入进去。ReflectiveMethodInvocation源码,外部使用这个出发拦截器链。

public Object proceed() throws Throwable {// 检查是否到达链末端if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {return invokeJoinpoint(); // 执行业务方法}// 获取下一个拦截器Object interceptorOrInterceptionAdvice =this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);// 递归调用下一个拦截器 ▼▼▼ 核心递归点 ▼▼▼return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
二、执行流程全景解析
proceed()方法拦截器1拦截器2业务方法调用invoke(this)执行前置逻辑调用proceed()调用invoke(this)执行前置逻辑调用proceed()执行原始业务方法返回结果返回结果执行后置逻辑返回结果执行后置逻辑返回结果proceed()方法拦截器1拦截器2业务方法

三、后置增强的逻辑

后置增强并非独立的拦截器节点,而是通过递归返回机制实现的:

1. 拦截器的标准结构
public class MyInterceptor implements MethodInterceptor {public Object invoke(MethodInvocation mi) throws Throwable {// 前置逻辑System.out.println("Before business method");// 关键:递归调用链Object result = mi.proceed();// 后置逻辑System.out.println("After business method");return result;}
}
2. 执行栈展开过程
// 伪代码表示执行栈
Stack:
1. MyInterceptor.invoke() -> 调用 mi.proceed()2. ReflectiveMethodInvocation.proceed() -> 调用下一个拦截器... 递归直到最后一个 ...N. ReflectiveMethodInvocation.proceed()-> 执行原始方法-> 返回结果// 栈开始展开
N-1. 上一个拦截器收到结果-> 执行后置逻辑-> 返回结果... 递归返回 ...1. 第一个拦截器收到结果-> 执行后置逻辑-> 返回最终结果

四、源码验证:Spring 内置拦截器实现

1. 后置返回通知 (AfterReturningAdviceInterceptor)
public Object invoke(MethodInvocation mi) throws Throwable {// 前置:无操作// 关键:先执行后续链(包含业务方法)Object retVal = mi.proceed();// 后置:在业务方法返回后执行this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());return retVal;
}
2. 最终通知 (AspectJAfterAdvice)
public Object invoke(MethodInvocation mi) throws Throwable {try {// 关键:先执行后续链return mi.proceed();} finally {// 后置:在finally块中确保执行invokeAdviceMethod();}
}

执行顺序

遍历preHandle
Interceptor1.pre
Interceptor2.pre
Interceptor3.pre
Controller
逆序postHandle
Interceptor3.post
Interceptor2.post
Interceptor1.post

三、拦截器方法与 AOP 节点的关系

1. MVC 拦截器 vs AOP 拦截器
特性MVC 拦截器方法AOP 拦截节点
执行位置preHandle/postHandleMethodInterceptor.invoke()
调用方式遍历调用链式递归调用
目标对象Controller 方法任意 Spring Bean 方法
访问权限只能访问 HTTP 请求/响应能访问方法参数、返回值、目标对象
是否共享节点❌ 独立于 AOP 链✅ 是 AOP 链的一部分
2. 关键区别图示
graph TBsubgraph HTTP请求流程Filter[Servlet过滤器] --> Interceptor[MVC拦截器]Interceptor --> Dispatcher[DispatcherServlet]endsubgraph Spring处理流程Dispatcher --> Proxy[Controller代理对象]Proxy --> AOP[AOP拦截链]AOP --> Bean[原始Controller方法]endnote[重要:MVC拦截器在AOP代理之外执行]

四、自定义组件加入位置

1. Servlet 过滤器加入点
@Configuration
public class FilterConfig {@Beanpublic FilterRegistrationBean<MyFilter> myFilter() {FilterRegistrationBean<MyFilter> bean = new FilterRegistrationBean<>();bean.setFilter(new MyFilter());bean.setOrder(1); // ▶ 关键:通过order控制递归顺序 ◀bean.addUrlPatterns("/*");return bean;}
}
2. MVC 拦截器加入点
@Configuration
public class WebConfig implements WebMvcConfigurer {@Overridepublic void addInterceptors(InterceptorRegistry registry) {// ▶ 加入遍历列表,按注册顺序执行 ◀registry.addInterceptor(new AuthInterceptor()).order(1) // 可选排序.addPathPatterns("/api/**");}
}

五、执行流程全景图

ClientFilter1Filter2DispatcherServletMVC InterceptorAOP InterceptorControllerHTTP Request前置处理chain.doFilter()前置处理chain.doFilter()preHandle()true/false进入代理拦截器1拦截器2目标方法结果拦截器后处理返回postHandle()直接返回alt[继续执行][中断]后置处理返回后置处理HTTP ResponseClientFilter1Filter2DispatcherServletMVC InterceptorAOP InterceptorController

六、技术栈分层架构

HTTP请求
Servlet容器层
Servlet过滤器
Spring Web层
MVC拦截器
Controller代理
Spring AOP层
业务拦截器
原始Bean方法

总结

  1. 调用机制本质

    • 过滤器:显式递归调用(必须调用 chain.doFilter()
    • MVC拦截器:隐式遍历调用(框架自动控制)
    • AOP拦截器:链式递归调用(通过 proceed() 传递)
  2. 与AOP节点的关系

    • MVC拦截器 不是 AOP链的一部分
    • Controller方法的执行会进入AOP代理链
    • MVC拦截器在AOP代理链 之前 执行
  3. 自定义组件加入

    • 过滤器:通过 FilterRegistrationBean 加入Servlet容器调用链
    • MVC拦截器:通过 WebMvcConfigurer 加入Spring MVC遍历列表
    • AOP拦截器:通过 @Aspect 加入Spring AOP代理链

理解这些差异对于构建高效、可维护的Web应用至关重要:

  • 使用过滤器处理底层HTTP问题(编码/安全)
  • 使用MVC拦截器处理请求生命周期(认证/日志)
  • 使用AOP拦截器处理业务逻辑(事务/性能监控)

这种分层设计让每个组件都能在最适合的层级发挥作用,既保持职责分离,又能协同完成复杂请求处理!

http://www.dtcms.com/a/332863.html

相关文章:

  • Spring容器初始化源码解析
  • 深入解析MPLS网络中的路由器角色
  • 【java】对word文件设置只读权限
  • HTTP/2新型漏洞“MadeYouReset“曝光:可发动大规模DoS攻击
  • 代码随想录Day51:图论(岛屿数量 深搜广搜、岛屿的最大面积)
  • C#文件复制异常深度剖析:解决“未能找到文件“之谜
  • Ceph CSI 镜像删除流程与 Trash 机制失效问题分析文档
  • CISC 与 RISC 架构全面解析:从原理到应用
  • gulimall项目笔记:P54三级分类拖拽功能实现
  • 《Attention-driven GUI Grounding》论文精读笔记
  • CSS Houdini 与 React 19 调度器:打造极致流畅的网页体验
  • 【Redis】Redis典型应用——分布式锁
  • 【Redis】分布式系统的演化过程
  • KNN 算法
  • 高频量化详解,速度和程序化的满足!
  • 卷积神经网络(CNN)学习笔记
  • 基本电子元件:贴片电阻器的种类
  • 序列晋升6:ElasticSearch深度解析,万字拆解
  • Spring事物
  • 如何理解AP中SM中宿主进程?
  • 艾伦·图灵:计算理论与人工智能的奠基人
  • 云原生俱乐部-k8s知识点归纳(4)
  • 数据结构初阶:排序算法(一)插入排序、选择排序
  • uniapp纯前端绘制商品分享图
  • 18- 网络编程
  • 【学习笔记】Java并发编程的艺术——第10章 Executor框架
  • 从PDF到洞察力:基于飞算JavaAI的智能文档分析引擎实战
  • canoe面板中的进度条的使用
  • 分享一个基于Hadoop的二手房销售签约数据分析与可视化系统,基于Python可视化的二手房销售数据分析平台
  • AI工作流入门指南:从概念到实践