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

Spring——Spring开发实战经验(4)

摘要

本文深入探讨了 Spring 应用中 Interceptor(拦截器)、Filter(过滤器)和 Aspect(切面)的执行顺序、职责及典型使用场景。Filter 是 Servlet 级别的机制,主要用于日志记录、权限验证等,它在请求到达 Spring MVC 的 DispatcherServlet 前执行,响应返回时按配置顺序反向执行。Interceptor 是 Spring 提供的机制,用于拦截 Spring MVC 请求,它在请求进入 Spring MVC 处理之前、Controller 方法执行之前和之后执行。Aspect(AOP)则用于处理横切关注点,如事务管理、日志记录等,它通过代理机制在目标方法执行前后插入额外逻辑。文中还提供了 WebMvcConfig 配置示例、拦截器与其他组件的对比以及拦截器与 AOP 的区别和联系等内容,帮助读者更好地理解和使用这些机制。

1. Interceptor/Filter/Aspect 的执行顺序

在 Spring 应用中,InterceptorFilterAspect 都是用来处理请求的不同机制。它们各自有不同的职责和执行顺序。理解它们的执行顺序对于调试和优化应用非常重要。

1.1. Filter(过滤器)

职责Filter是一种 Servlet 级别的机制,主要用于请求和响应的预处理和后处理。它通常用于日志记录、权限验证、请求修改等操作。

执行顺序Filter 在 Servlet 容器中非常早地被调用,并且它在请求到达 Spring MVC 的处理器之前执行。

执行顺序:

  1. 请求到达:Filter 在请求到达 Spring MVC 的 DispatcherServlet 前执行。
  2. Filter 执行:所有配置的 Filter 按照配置顺序依次执行。
  3. 请求交给 DispatcherServlet:Filter 在请求到达 DispatcherServlet 时,会允许请求继续向下传递。
  4. 响应返回:响应从 DispatcherServlet 返回时,Filter 会按配置顺序反向执行(从最后一个 Filter 到第一个 Filter)。

典型使用场景

  • 日志记录
  • 权限校验
  • 请求数据修改
  • 响应数据修改

1.2. Interceptor(拦截器)

  • 职责Interceptor 是 Spring 提供的机制,它用于拦截 Spring MVC 请求。与 Filter 不同的是,Interceptor 是基于 Spring 的控制器和 HandlerMapping 的,并且它只与 Spring MVC 控制器交互。
  • 执行顺序Interceptor 在请求进入 Spring MVC 处理之前、Controller 方法执行之前和之后执行。

执行顺序:

  1. 请求到达 DispatcherServlet:当请求到达 DispatcherServlet 时,Interceptor 会按配置顺序依次执行。
  2. 执行 Controller 方法Interceptor 执行完成后,DispatcherServlet 会调用 Controller 层的处理方法。
  3. 响应返回:当 Controller 方法返回结果后,Interceptor 会按配置顺序反向执行,直到最后一个 Interceptor

典型使用场景

  • 权限验证
  • 请求计时
  • 处理请求日志

3. Aspect (AOP)(切面)

  • 职责Aspect 是基于切面编程(AOP)机制的,用于在方法执行前后增加额外的行为(如日志记录、事务处理等)。它是通过 @Aspect 注解和切点(@Before@After@Around 等)来定义的。
  • 执行顺序Aspect 是 Spring AOP 的一部分,AOP 执行顺序通常是基于方法执行的前后,而不是请求/响应的生命周期。它通常是在 Controller 方法执行前后,或者 Service/DAO 层方法执行前后 进行拦截。

执行顺序:

  1. 请求到达 DispatcherServlet:在这个阶段,InterceptorFilter 会先执行。
  2. Controller 方法执行Aspect 会在方法执行前后执行,具体的顺序取决于通知的类型(例如 @Before@After@Around 等)。
    • @Before:在目标方法执行前执行。
    • @After:在目标方法执行后执行。
    • @Around:可以在方法执行前后都执行。
  1. 响应返回:响应返回时,Aspect 会根据 @After@AfterReturning 等通知继续执行。

典型使用场景

  • 日志记录
  • 事务管理
  • 安全校验

执行顺序总结:

阶段

Filter

Interceptor

Aspect

请求到达 DispatcherServlet

首先执行(Filter Chain)

最后执行(Spring 容器配置的顺序)

不影响请求进入 DispatcherServlet

Controller 方法执行前

不参与

执行前通知 (preHandle

)

执行前通知 (@Before

@Around

)

Controller 方法执行后

不参与

执行后通知 (postHandle

)

执行后通知 (@After

@Around

)

响应返回

反向执行(Filter Chain)

反向执行(Spring 容器配置的顺序)

执行后通知 (@AfterReturning

@After

)

执行顺序图解

  1. FilterInterceptorController 方法InterceptorFilter (请求方向)
  2. FilterInterceptorController 方法InterceptorFilter (响应方向)

实用场景示例:

假设有如下情形:

  • 你需要在每个请求的最前面进行身份验证,可以使用 Filter 来实现。
  • 你需要在控制器方法执行之前和之后记录日志或进行权限校验,可以使用 Interceptor 来实现。
  • 你需要在特定方法执行前后做日志记录、事务管理等操作,可以使用 Aspect 来实现。

补充说明

  • Filter 是 Java EE 标准的机制,直接作用于 Servlet 容器,独立于 Spring。
  • Interceptor 是 Spring 特有的功能,作用于 Spring MVC 处理的请求。
  • Aspect 是 Spring AOP 提供的功能,可以用来处理横切关注点,适用于方法级别的增强。

通过合理的使用 FilterInterceptorAspect,你可以实现非常灵活的请求处理、日志记录、安全校验等功能。

2. WebMvcConfig配置示例

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

    @Resource
    private PermissionInterceptor permissionInterceptor;
    @Resource
    private CookieInterceptor cookieInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(permissionInterceptor).addPathPatterns("/**");
        registry.addInterceptor(cookieInterceptor).addPathPatterns("/**");
    }

}

这是一个 Spring MVC 的配置类,WebMvcConfig 实现了 WebMvcConfigurer 接口,主要用于配置和定制 Spring MVC 的行为。以下是代码中的关键点:

  • @Configuration:标注该类为一个配置类,Spring 容器会将其识别为 Bean 定义的来源。
  • WebMvcConfigurer:这是一个 Spring 提供的接口,允许我们通过实现其方法来自定义 Spring MVC 的配置。
  • @Resource:用于注入 Spring 容器中的 Bean。这里注入了两个拦截器:
  • permissionInterceptor:权限拦截器,用于处理与用户权限相关的逻辑。
  • cookieInterceptor:Cookie 拦截器,用于处理与 Cookie 验证或操作相关的逻辑。
  • addInterceptors 方法:这个的是实现WebMvcConfigurer的方法。用来向 Spring MVC 的拦截器链中添加拦截器。
  • InterceptorRegistry:拦截器注册器,用于配置拦截器及其作用路径。
  • addInterceptor(permissionInterceptor).addPathPatterns("/**")
  • permissionInterceptor 注册到拦截器链。
  • addPathPatterns("/**") 表示拦截所有请求路径。
  • addInterceptor(cookieInterceptor).addPathPatterns("/**"):同样注册 cookieInterceptor 拦截所有请求路径。

拦截器执行顺序:拦截器会按照注册顺序依次执行(即先执行 permissionInterceptor,再执行 cookieInterceptor)。

package org.springframework.web.servlet.config.annotation;

import java.util.List;
import org.springframework.format.FormatterRegistry;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.lang.Nullable;
import org.springframework.validation.MessageCodesResolver;
import org.springframework.validation.Validator;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
import org.springframework.web.servlet.HandlerExceptionResolver;

public interface WebMvcConfigurer {
    default void configurePathMatch(PathMatchConfigurer configurer) {
    }

    default void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
    }

    default void configureAsyncSupport(AsyncSupportConfigurer configurer) {
    }

    default void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
    }

    default void addFormatters(FormatterRegistry registry) {
    }

    default void addInterceptors(InterceptorRegistry registry) {
    }

    default void addResourceHandlers(ResourceHandlerRegistry registry) {
    }

    default void addCorsMappings(CorsRegistry registry) {
    }

    default void addViewControllers(ViewControllerRegistry registry) {
    }

    default void configureViewResolvers(ViewResolverRegistry registry) {
    }

    default void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
    }

    default void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> handlers) {
    }

    default void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
    }

    default void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
    }

    default void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) {
    }

    default void extendHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) {
    }

    @Nullable
    default Validator getValidator() {
        return null;
    }

    @Nullable
    default MessageCodesResolver getMessageCodesResolver() {
        return null;
    }
}

这段代码定义了 WebMvcConfigurer 接口,它是 Spring MVC 配置的核心接口之一。通过实现这个接口,开发者可以自定义 Spring MVC 的各种行为,包括路径匹配、内容协商、异步支持、默认 Servlet 处理、格式化器、拦截器、资源处理器、跨域映射、视图控制器、视图解析器、参数解析器、返回值处理器、消息转换器、异常处理器以及验证器和消息代码解析器。

3. Spring 中拦截器

Spring MVC的拦截器 (HandlerInterceptor) 是一种 AOP(面向切面编程) 的实现机制,允许在请求处理的不同阶段拦截 HTTP 请求并执行特定逻辑。以下是拦截器的主要作用:

3.1. 拦截器工作流程

  1. 触发时机:
    • 拦截器在请求到达控制器(@Controller@RestController)之前执行。
    • 响应生成后,在发送给客户端之前再次执行。
  1. 主要方法:
    • preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
      • 在请求到达控制器之前执行。
      • 返回 true 表示继续处理请求;返回 false 表示中止请求。
    • postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
      • 在控制器处理完请求后,但尚未生成响应之前执行。
    • afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
      • 在视图渲染完成后执行,用于资源清理或记录日志。

3.2. 拦截器常见应用场景

  1. 权限校验(如 PermissionInterceptor):
    • 判断用户是否有权限访问某些接口。
    • 如果没有权限,直接返回错误响应(如 403 Forbidden)。
  1. 认证与登录验证
    • 验证用户是否已登录,检查 SessionToken
    • 如果未登录,跳转到登录页面或返回 401 Unauthorized。
  1. 请求日志记录
    • 记录请求的参数、响应结果、执行时间等信息,用于监控和分析。
  1. 参数校验与数据预处理
    • 检查请求中的参数是否合法。
    • 为请求添加必要的上下文数据(如用户信息、请求头补充)。
  1. 跨站请求伪造(CSRF)防护
    • 检查请求头中的 CSRF Token 是否有效。
  1. 请求追踪与调试
    • 生成唯一的请求 ID,用于追踪请求链路。

3.3. 拦截器与其他组件的对比

特性

拦截器 (Interceptor)

过滤器 (Filter)

切面 (AOP Aspect)

触发阶段

Spring MVC 的处理流程内

Servlet 请求的早期阶段

方法级别(如 @Controller

方法调用)

关注点

与请求处理相关(权限、认证等)

全局请求过滤(编码、跨域等)

与业务逻辑相关(如日志、事务管理)

实现接口

HandlerInterceptor

javax.servlet.Filter

@Aspect

(基于 Spring AOP)

应用场景

请求认证、权限校验、日志记录等

请求过滤、跨域、编码设置等

日志、事务处理、通用逻辑

4. 拦截器与AOP区别

拦截器(Interceptor)虽然与 AOP(面向切面编程) 有相似之处,但严格来说,拦截器并不是 AOP 的直接实现,而是一个独立的机制。二者有不同的设计目的和实现方式,但在某些场景下确实可以通过拦截器实现类似于 AOP 的功能。下面详细分析它们的区别和联系。

4.1. 拦截器与 AOP 的区别

4.1.1. 核心概念不同

  • AOP(Aspect-Oriented Programming)
    • 是一种面向切面编程的设计思想,用于在不改变核心业务逻辑的情况下,动态地为方法添加额外行为。
    • 通过 切面(Aspect)切入点(Pointcut) 的定义,精准定位到某些方法调用,并在方法执行的 前后或异常时 添加逻辑。
    • 主要基于 Spring AOP(代理模式) 或 AspectJ(字节码增强)。
  • 拦截器(Interceptor)
    • 是 Spring MVC 或其他框架提供的一种机制,用于对 HTTP 请求和响应 进行拦截和处理。
    • 通常应用在 Web 请求的处理链路 中,比如在请求到达控制器之前,或响应生成之后添加逻辑。

4.1.2. 工作范围不同

  • AOP
    • 应用于方法级别,主要是对业务方法(如 @Service@Controller)进行增强。
    • 可以在任何类的方法上进行增强,甚至独立于 Spring MVC。
  • 拦截器
    • 专注于处理 HTTP 请求和响应,属于 Spring MVC 流程 的一部分。
    • 作用范围是 Controller(控制器)方法之前和之后

4.1.3. 触发机制不同

  • AOP
    • 基于代理模式(JDK 动态代理或 CGLIB 动态代理)或字节码操作(如 AspectJ)。
    • 使用切面定义,依赖切入点表达式(如 execution())。
    • 仅对特定的方法调用生效,与 HTTP 请求无关。
  • 拦截器
    • 工作在 Spring MVC 的处理链中,由 DispatcherServlet 调度执行。
    • 对 HTTP 请求进行预处理(如认证、日志、跨域检查等)。

4.2. 拦截器是否可以实现 AOP 的功能?

在某些场景下,拦截器确实可以实现类似 AOP 的功能,例如:

  • 记录日志: 在拦截器的 preHandle 方法中记录请求的参数。
  • 权限校验: 在拦截器中判断是否有访问权限,阻止不合法请求。

但拦截器的能力有限:

  1. 它只能拦截基于 HTTP 的请求,无法对方法调用(非 HTTP 场景)进行增强。
  2. 它无法精准到某个类或方法,而是基于请求路径。

AOP 更灵活和强大,适合以下场景:

  • 精准增强特定方法(通过切入点)。
  • 跨服务的通用逻辑(如事务管理、性能监控)。

4.3. 拦截器与 AOP 的联系

  • 二者的功能在某些场景下重叠。例如,拦截器可以在请求进入 Controller 前后,记录日志或进行校验,这与 AOP 的切面功能相似。
  • 在 Spring 应用中,AOP 和拦截器经常配合使用
    • 拦截器处理全局的 HTTP 请求级别逻辑。
    • AOP 处理业务方法级别的切面逻辑。

4.4. 拦截器和 AOP 的对比表

特性

AOP

拦截器(Interceptor)

作用范围

方法级别(类、方法的调用)

请求级别(HTTP 请求前后)

依赖机制

动态代理(JDK Proxy 或 CGLIB)

Spring MVC 的 HandlerInterceptor

主要应用场景

日志、事务管理、性能监控、方法增强等

请求认证、权限校验、跨域、统一日志等

触发点

方法调用(如 @Service

方法)

HTTP 请求的处理过程

实现方式

@Aspect

(Spring AOP 或 AspectJ)

实现 HandlerInterceptor

接口

局限性

无法直接作用于 HTTP 请求

无法精确到特定方法,强依赖 Spring MVC

4.5. 示例对比

4.5.1. AOP 切面示例

@Aspect
@Component
public class LoggingAspect {

    @Pointcut("execution(* com.example.service.*.*(..))")
    public void serviceMethods() {}

    @Before("serviceMethods()")
    public void logBefore(JoinPoint joinPoint) {
        System.out.println("Before method: " + joinPoint.getSignature().getName());
    }
}
  • 作用:com.example.service 包中的所有方法执行之前记录日志。

4.5.2. 拦截器示例

public class LoggingInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        System.out.println("Before handling request: " + request.getRequestURI());
        return true;
    }
}
  • 作用: 在每次 HTTP 请求到达 Controller 之前记录请求路径。

4.6. 总结

  • 拦截器不是 AOP 的实现,但它们的功能在某些场景下有重叠。
  • 拦截器 更偏向于 HTTP 请求级别的拦截,而 AOP 更灵活,适合方法级增强。
  • 在复杂项目中,拦截器和 AOP 通常配合使用,实现从请求级别到方法级别的逻辑分离。

博文参考

相关文章:

  • SpringBoot 的核心只有几张图
  • Ubuntu 24.04.1 LTS 本地部署 DeepSeek 私有化知识库
  • C语言中的强制类型转换:原理、用法及注意事项
  • 1.buuctf [BJDCTF2020]EasySearch
  • Hadoop之HDFS的使用
  • 从零开始:Gitee 仓库创建与 Git 配置指南
  • 服务器硬件知识--------linux系统初识and安装
  • Linux csplit 命令实现日志文件的拆分
  • 软考高级《系统架构设计师》知识点(五)
  • Spring事务原理的具体实现,以及包括源码以及具体在实际项目中的使用。
  • 【etcd】etcd_APIs 简单KV、watch、lease、txn命令
  • 数据结构-顺序表
  • 东方财富股吧发帖与评论爬虫
  • 基于腾讯云TI-ONE 训练平台快速部署和体验 DeepSeek 系列模型
  • 「AI学习笔记」机器学习与深度学习的区别:从技术到产品的深度解析(四)...
  • 如何高效利用 AI 工具提升开发效率?
  • 机器学习PCA和LDA
  • du-磁盘占用管理
  • 基于Python实现的缓存淘汰替换策略算法,该算法将缓存分区
  • MongoDB 架构设计:深入解析核心组件与工作原理
  • 节前A股持续震荡,“五一”假期持股还是持币过节胜率更高?
  • 看展览|建造上海:1949年以来的建筑、城市与文化
  • 千亿市值光储龙头董事长向母校合肥工业大学捐赠1亿元
  • 暴涨96%!一季度“中国游中国购”持续升温,还有更多利好
  • 第二部以“法典”命名的法律!生态环境法典编纂迈出“关键步”
  • 俄罗斯称已收复库尔斯克州,普京发表讲话