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

Spring AOP @Before (前置通知): 在目标方法执行前做什么?

在这里插入图片描述

核心定义

@Before 是 Spring AOP 中的一种**通知(Advice)**类型。它的核心作用是:

在“连接点(Join Point)”,也就是目标方法被执行之前,执行一段特定的逻辑代码。

你可以把它想象成一个“门卫”。在有人(调用方)要进入一个重要的房间(目标方法)之前,门卫(@Before 通知)会先执行一系列检查或准备工作,比如核对身份、记录来访时间等。


@Before 通知能做什么?(主要应用场景)

前置通知非常适合执行一些“准备”或“预检”性质的任务,这些任务不影响目标方法的执行结果,但对整个流程至关重要。

  1. 日志记录 (Logging/Auditing)

    • 这是最经典的应用。在方法执行前,记录下谁、在什么时间、尝试调用哪个方法,并传入了什么参数。
    • 示例:“用户 admin 正在尝试执行 updateProduct 操作,参数为: Product{id=101, name='New Laptop'}”。
  2. 权限校验 (Authorization/Security Check)

    • 在执行敏感操作(如删除数据、修改金额)前,检查当前登录的用户是否拥有足够的权限。
    • 如果没有权限,可以直接在 @Before 通知里抛出一个异常(如 PermissionDeniedException),这样目标方法就根本不会被执行,从而保证了系统的安全。
  3. 参数校验 (Parameter Validation)

    • 虽然 JSR-303/JSR-380 (Bean Validation) 是更通用的方式,但对于一些复杂的、跨领域的业务校验,使用 AOP 也很方便。
    • 例如,检查传入的参数是否为 null,数值是否在有效范围内等。如果校验失败,同样可以抛出异常来中断操作。
  4. 数据准备 (Data Preparation)

    • 在方法执行前,可能需要准备一些上下文环境信息。
    • 例如,将某些信息设置到 ThreadLocal 中,以便目标方法或后续的逻辑可以方便地获取。
  5. 开启事务或设置事务属性(不推荐,但技术上可行)

    • 虽然 Spring 提供了更强大的 @Transactional 注解来管理事务,但理论上你也可以在 @Before 中手动开启一个事务。不过,这种方式不推荐。

@Before 的一个关键特点:无法阻止目标方法执行(除非抛异常)

@Before 通知本身没有“否决权”。一旦 @Before 的代码成功执行完毕(没有抛出任何异常),控制权会自动交还给 AOP 框架,然后目标方法会被继续执行

  • 唯一能阻止目标方法执行的方式:在 @Before 通知的代码中主动抛出一个异常。异常会中断当前的执行流程,使得目标方法没有机会被调用。

如果你需要更复杂的控制,比如:

  • 根据条件决定是否执行目标方法。
  • 修改传入目标方法的参数。
  • 修改目标方法的返回值。

那么你应该使用功能更强大的 @Around (环绕通知)


代码示例

让我们看一个具体的例子,实现一个简单的日志记录功能。

1. 添加 AOP 依赖 (Maven)

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId>
</dependency>

2. 创建一个业务服务类 (目标对象)

package com.example.service;import org.springframework.stereotype.Service;@Service
public class UserService {public String findUserById(Long id) {System.out.println("--- 核心业务逻辑:正在根据 ID 查询用户... ---");if (id < 1) {throw new IllegalArgumentException("用户ID必须大于0");}return "User" + id;}
}

3. 创建一个切面 (Aspect) 并定义 @Before 通知

package com.example.aop;import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import java.util.Arrays;@Aspect  // 声明这是一个切面类
@Component // 将其注册为 Spring Bean
public class LoggingAspect {// 1. 定义一个可重用的切点 (Pointcut)// 拦截 com.example.service 包下所有类的所有公共方法@Pointcut("execution(public * com.example.service.*.*(..))")public void serviceLayerPointcut() {}// 2. 定义前置通知,并引用上面的切点@Before("serviceLayerPointcut()")public void logBefore(JoinPoint joinPoint) { // JoinPoint 对象包含了目标方法的信息// 获取方法签名String methodName = joinPoint.getSignature().getName();// 获取方法参数Object[] args = joinPoint.getArgs();System.out.println("==================================================");System.out.printf("[AOP 前置通知]: 方法 [%s] 即将执行...%n", methodName);System.out.printf("[AOP 前置通知]: 参数为: %s%n", Arrays.toString(args));System.out.println("==================================================");}
}

4. 运行代码

当你调用 userService.findUserById(101L) 时,控制台的输出会是:

==================================================
[AOP 前置通知]: 方法 [findUserById] 即将执行...
[AOP 前置通知]: 参数为: [101]
==================================================
--- 核心业务逻辑:正在根据 ID 查询用户... ---

可以看到,logBefore 方法(前置通知)在 findUserById 方法(目标方法)之前被成功执行了。

总结

特性描述
执行时机在目标方法被调用之前执行。
核心用途日志记录、权限校验、参数校验、数据准备等预处理工作。
控制能力不能直接阻止目标方法执行,也不能修改参数或返回值。
如何中断流程只能通过抛出异常来间接阻止目标方法的执行。
关键参数可以注入 JoinPoint 对象,用以获取目标方法的签名、参数等元数据。

简而言之,@Before 是一个强大而简单的工具,用于在核心业务逻辑开始前“插入”一段通用的横切逻辑。

http://www.lqws.cn/news/443161.html

相关文章:

  • 智能家居HA篇 二、配置Home Assistant并实现外部访问
  • android 省市区联动选择
  • 计算机视觉阶段一:CV入门基础
  • Xsens动作捕捉技术用于研究机器人的运动控制、姿态调整以及人机交互
  • .NET 的配置系统
  • 【Mini-F5265-OB开发板试用测评】2、PWM驱动遥控车RX2接收解码带马达驱动控制IC
  • 华为OD机试_2025 B卷_构成正方形数量(Python,100分)(附详细解题思路)
  • 如何获取Java对象的大小
  • MQTT 消息队列传输协议(Message Queuing Telemetry Transport)
  • 【深度学习】生成对抗网络(GANs)深度解析:从理论到实践的革命性生成模型
  • 优化 Python 爬虫性能:异步爬取新浪财经大数据
  • 46道Jenkins高频题整理(附答案背诵版)
  • Jenkins通过Pipeline流水线方式编译Java项目
  • IP 地理库的使用指南:从基础应用到深度实践​
  • Redis 持久化机制详解:RDB、AOF 原理与面试最佳实践(AOF篇)
  • IntersectionObserver API应用场景示例代码详解
  • 医疗低功耗智能AI网络搜索优化策略
  • jquery 赋值时不触发change事件解决——仙盟创梦IDE
  • Kafka性能压测报告撰写
  • Outlook邮箱开通发信服务及OAuth2验证开通
  • 靶场(二十五)---小白心得靶场体会---Access
  • 基于Python+PySide6构建的夸克网盘批量工具,支持批量转存与分享
  • 使用NPOI库导出多个Excel并压缩zip包
  • Qt 解析复杂对象构成
  • 基于C#的Baumer相机二次开发教程
  • VACM 详解:SNMPv3 的访问控制核心
  • 基于大模型的急性结石性胆囊炎全流程预测与诊疗方案研究
  • 小白畅通Linux之旅-----Rsync+sersync实现数据实时同步
  • 九九乘法表
  • [Data Pipeline] Kafka消息 | Redis缓存 | Docker部署(Lambda架构)