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

Spring AOP 完整教程(中篇)

承接上篇 AOP 基础概念与计时入门案例,本篇为进阶核心内容,详细讲解 5 类通知执行时机、@Pointcut 复用切点、两种切点表达式语法、JoinPoint 连接点 API、多切面执行优先级控制,配套完整可运行代码、执行流程对比,是面试高频核心考点,下篇将结合 ThreadLocal 完成操作日志综合实战。

一、五大通知(Advice)类型全解

通知就是切面中封装的增强逻辑,根据执行时机分为 5 种,各自执行顺序、使用场景差异巨大。

1. @Around 环绕通知【重中之重,企业最常用】

  1. 执行时机:目标方法执行前、执行后都会执行;
  2. 独有特性:唯一可以手动控制原始方法是否执行;
  3. 必须调用pjp.proceed()才会执行目标业务方法;
  4. 方法返回值必须是 Object,用来接收目标方法返回的数据;
  5. 优势:可捕获异常、记录入参、返回值、计算耗时,一站式完成日志统计。完整示例代码:
@Slf4j @Aspect @Component public class TimeAspect { @Around("execution(* com.itheima.service.impl.*.*(..))") public Object around(ProceedingJoinPoint pjp) throws Throwable { log.info("【环绕前置】方法即将执行"); long start = System.currentTimeMillis(); // 执行原始目标方法 Object result = pjp.proceed(); long end = System.currentTimeMillis(); log.info("【环绕后置】方法执行完成,耗时{}ms", end - start); return result; } }

2. @Before 前置通知

目标方法运行之前执行,无法拦截、修改返回值,不能控制方法是否执行。适用场景:打印请求参数、权限校验前置判断。

@Before("execution(* com.itheima.service.impl.*.*(..))") public void before(JoinPoint jp){ log.info("【前置通知】准备调用方法:{}",jp.getSignature().getName()); }

3. @After 后置通知

目标方法执行完毕后执行,无论正常结束、抛出异常都会执行,类似代码块 finally。适用场景:统一资源释放、后置收尾打印。

4. @AfterReturning 返回通知

仅当目标方法无异常正常执行完毕才会触发;方法抛异常则不会执行。适用场景:记录接口正常返回数据。

5. @AfterThrowing 异常通知

只有目标方法抛出异常时才执行,正常走完不会触发。适用场景:全局异常日志记录、异常告警推送。

两种执行顺序演示

  1. 无异常完整执行顺序@Around 前置逻辑 → @Before → 目标方法执行 → @AfterReturning → @After → @Around 后置逻辑
  2. 目标方法抛出异常顺序@Around 前置逻辑 → @Before → 方法抛异常 → @AfterThrowing → @After

注:环绕通知内可手动 try-catch 捕获异常,阻断异常向外抛出。

二、@PointCut 抽取公共切点表达式

使用场景

项目多处切面复用同一套匹配规则,重复书写 execution 表达式冗余,使用@Pointcut注解抽取统一切点,一处定义多处引用。

代码示例

@Slf4j @Aspect @Component public class TimeAspect { // 抽取公共切点,匹配所有业务层方法 @Pointcut("execution(* com.itheima.service.impl.*.*(..))") public void servicePoint(){} // 直接引用切点方法名,无需重复写表达式 @Around("servicePoint()") public Object around(ProceedingJoinPoint pjp) throws Throwable { long start = System.currentTimeMillis(); Object res = pjp.proceed(); log.info("执行耗时:{}ms",System.currentTimeMillis()-start); return res; } @Before("servicePoint()") public void before(JoinPoint jp){ log.info("即将执行方法:{}",jp.getSignature().getName()); } }

访问权限说明

  1. private 修饰:仅当前切面类内部可以引用;
  2. public 修饰:其他切面类也能引用该切点。

三、两种主流切入点表达式

方式 1:execution 方法匹配表达式(全量拦截专用)

根据包、类、方法名、返回值、参数精准匹配方法,是入门计时案例使用的表达式。

完整标准语法
execution(访问修饰符? 返回值 包名.类名.?方法名(参数) throws 异常?)

?代表可省略内容;访问修饰符默认不写(匹配 public)。

两大通配符规则
  1. *:单个任意匹配;可匹配返回值、包名、类名、单个参数;
  2. ..:多层连续匹配;可匹配多级包、任意数量任意参数。
常用匹配示例
// 匹配itheima下所有service包所有类所有方法 execution(* com.itheima..service.*.*(..)) // 匹配controller下所有save/update/delete开头的增删改接口 execution(* com.itheima.controller.*.save*(..)) || execution(* com.itheima.controller.*.update*(..)) || execution(* com.itheima.controller.*.delete*(..)) // 匹配返回值void、无参数方法 execution(void com.itheima.service.impl.*.*())
书写规范建议
  1. 缩小匹配范围,尽量不用..泛匹配全项目,减少拦截性能损耗;
  2. 优先匹配接口而非实现类,拓展性更强。

方式 2:@annotation 注解匹配(按需拦截专用)

自定义标记注解,仅拦截添加该注解的方法,适合少量接口单独记录日志场景。

完整使用流程
  1. 自定义标记注解
import java.lang.annotation.*; @Target(ElementType.METHOD) // 仅作用在方法 @Retention(RUNTIME) public @interface LogRecord {}
  1. Controller 接口添加注解标记
@PostMapping("/dept/save") @LogRecord public Result save(Dept dept){ deptService.save(dept); return Result.success(); }
  1. 切面切点匹配注解
@Pointcut("@annotation(com.itheima.anno.LogRecord)") public void logPoint(){}

两种表达式选型对比

  1. 批量拦截整个包全部业务方法 → 选用 execution;
  2. 仅少量接口需要增强,灵活按需开启 → 选用 @annotation。

四、JoinPoint 连接点 API 获取方法信息

Spring 提供 JoinPoint 对象封装目标方法全部信息,不同通知使用对象有区分:

  1. ProceedingJoinPoint:仅 @Around 环绕通知可用,独有proceed()执行目标方法;
  2. Join:@Before/@After/@AfterReturning/@AfterThrowing 通用,无执行方法 API。

通用核心方法(两类对象均可调用)

// 获取目标类完整类名 String className = jp.getTarget().getClass().getName(); // 获取方法签名(方法名、返回值) Signature sig = jp.getSignature(); String methodName = sig.getName(); // 获取调用时传入的所有参数 Object[] args = jp.getArgs();

环绕通知独有方法

// 执行原始业务方法,必须调用否则目标逻辑不会执行 Object result = pjp.proceed();

完整代码示例

@Around("servicePoint()") public Object around(ProceedingJoinPoint pjp) throws Throwable { // 提取方法信息 String className = pjp.getTarget().getClass().getName(); String method = pjp.getSignature().getName(); Object[] params = pjp.getArgs(); log.info("执行类:{},方法:{},入参:{}",className,method,params); Object res = pjp.proceed(); return res; }

五、多切面执行顺序控制

项目中存在多个切面类(计时切面、日志切面、权限切面),同时匹配同一个目标方法时,执行顺序有默认规则,也可手动自定义优先级。

1. 默认排序规则

切面类名字母自然排序:

  • 前置通知:字母靠前的切面先执行;
  • 后置通知:字母靠前的切面后执行。

2. @Order 注解手动控制优先级

切面类添加@Order(数字),数字越小优先级越高;

  • 前置逻辑:数字小先执行;
  • 后置 / 异常逻辑:数字小后执行。示例:
@Order(1) // 优先级更高,前置先执行 @Aspect @Component public TimeAspect {} @Order(10) @Aspect @Component public LogAspect {}

执行流程举例

TimeAspect(Order1)、LogAspect(Order10)无异常场景:

  1. Time 环绕前置 → Log 环绕前置
  2. Time 前置 → Log 前置
  3. 执行目标方法
  4. Log 返回通知 → Time 返回通知
  5. Log 后置 → Time 后置
  6. Log 环绕后置 → Time 环绕后置

中篇全文总结

  1. 五大通知:@Around (核心)、@Before、@After、@AfterReturning、@AfterThrowing,区分有无异常的执行顺序;
  2. @Pointcut 抽取公共切点表达式,简化多处重复切点代码;
  3. 两种切点:execution 按包 / 方法批量匹配,@annotation 注解按需拦截;
  4. JoinPoint 获取类名、方法、参数,ProceedingJoinPoint 仅环绕可用,可执行目标方法;
  5. 多切面默认按类名字母排序,@Order 数字越小优先级越高。

中篇拓展实操练习

  1. 编写切面,同时实现 5 类通知,分别打印日志,观察有无异常两种执行顺序;
  2. 使用 @Pointcut 抽取 service 切点,分别在 @Before、@Around 复用;
  3. 自定义 @Log 注解,使用注解切点只拦截新增接口;
  4. 创建两个切面,添加 @Order 修改执行顺序,控制台打印验证。

中篇面试高频考点

  1. 五种通知分别在什么时机执行,异常场景执行差异;
  2. @Around 和其他通知最大区别是什么?
  3. execution 表达式中*..通配符含义;
  4. JoinPoint 和 ProceedingJoinPoint 区别、各自使用场景;
  5. 多个切面如何调整执行优先级。
http://www.jsqmd.com/news/1086780/

相关文章:

  • 微信好友检测终极指南:3步快速发现谁删除了你
  • AI驱动的肌电义肢:实时意图识别让智能假手真正听懂大脑
  • OmenSuperHub终极指南:解锁惠普暗影精灵游戏本性能的完整教程
  • KMS_VL_ALL_AIO:如何实现Windows与Office的一键智能激活?
  • 智能直播录制工具:如何实现7x24小时自动化录播管理
  • 量子相位估计TICC协议:突破控制开销瓶颈
  • 091、CodeX API 编程:用 OpenAI SDK 构建自定义 Agent 应用
  • AI 辅助学 Rust——大模型时代的编程学习新范式与方法论
  • Windows安卓应用安装器:告别模拟器,让安卓应用在电脑上原生运行
  • 终极AMD显卡驱动精简指南:如何用Radeon Software Slimmer让系统飞起来
  • Auto-Feed:PT站一键转载终极指南,彻底告别手动搬运
  • N_m3u8DL-RE:跨平台流媒体下载终极解决方案完整指南
  • 如何快速清理重复文件?dupeGuru完整指南帮你释放存储空间
  • 算法空间复杂度优化:原理、实践与未来趋势
  • RA8M1 SPI/OSPI事件输出与高速接口配置实战指南
  • AI Agent运行时商品化:Session事件日志与沙盒架构解析
  • 强力解锁QQ音乐:MCQTSS_QQMusic无损资源解析工具
  • 免费开源!三步将普通2D视频变成立体VR 3D视频的终极指南
  • 终极Jable视频下载解决方案:如何快速高效下载Jable.tv视频?
  • 【软考加分黄金窗口期】:错过2024下半年报名=自动放弃2025省考“隐形编制入场券”?
  • 5分钟免费AI视频生成:零基础成为数字导演的终极指南
  • 中兴光猫配置解密工具终极指南:5分钟掌握加密配置破解核心技术
  • 如何用Python缠论框架实现智能量化交易:从入门到实战
  • 解锁联想拯救者隐藏潜能:3个步骤让你的游戏本性能飙升50%
  • FPGA MultiBoot:从原理到实战,构建高可靠固件升级方案
  • Anthropic多次指控中国AI公司“蒸馏”,背后是产业竞争与地缘压力作祟?
  • 企业级xxl-job深度定制:从OpenGauss适配到统一权限融合实战
  • OpenRGB终极指南:告别多软件混乱,一个工具统一控制所有RGB灯光
  • RA8D2 MCU中断安全与NMI管理实战:TrustZone配置与故障处理
  • STM32与PAJ7620:从零构建手势交互系统