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

Spring AOP 中有多个切面时执行顺序是怎样的?

当多个切面(Aspect)的切点(Pointcut)都匹配到同一个连接点(方法)时,Spring AOP 需要一个明确的规则来决定这些切面(或通知)的执行顺序。

核心规则:@Order 注解或 Ordered 接口

Spring AOP 使用 @Order 注解 或实现 org.springframework.core.Ordered 接口 来定义切面的执行顺序。

  • @Order(value): 注解的值是一个整数。value 的值越小,切面的优先级越高,越先执行。
  • Ordered 接口: 实现这个接口需要重写 getOrder() 方法,返回一个整数。同样,返回值越小,优先级越高。

记忆技巧:可以想象成排队,号码越小(@Order(1))的人排在越前面,越先办理业务。

“洋葱模型”:切面的进入与退出顺序

多个切面的执行顺序遵循一个经典的“同心圆”或“洋葱模型”。优先级高的切面会“包裹”在优先级低的切面的外面。

这意味着:

  1. 进入阶段 (Before/Around前置部分)

    • @Order越小的切面,其 @Before@Around 的前置部分越先执行
  2. 退出阶段 (After/Around后置部分)

    • @Order越小的切面,其 @After@AfterReturning@AfterThrowing@Around 的后置部分越后执行(因为它在最外层,需要等待所有内层逻辑执行完毕)。

图解“洋葱模型”:

假设我们有两个切面:LoggingAspect (@Order(10))SecurityAspect (@Order(20))
优先级:LoggingAspect > SecurityAspect

<--  请求进入                                                     响应退出 -->
+-----------------------------------------------------------------------------+
|  LoggingAspect (@Order(10) - 优先级高,在最外层)                           |
|                                                                             |
|   @Before/Around前置 (先执行)                                               |
|                                                                             |
|      +------------------------------------------------------------------+   |
|      |  SecurityAspect (@Order(20) - 优先级低,在内层)                  |   |
|      |                                                                 |   |
|      |   @Before/Around前置 (后执行)                                    |   |
|      |                                                                 |   |
|      |      +------------------------------------------------------+   |   |
|      |      |                目标方法 (Target Method)              |   |   |
|      |      +------------------------------------------------------+   |   |
|      |                                                                 |   |
|      |   @After/Around后置 (先执行)                                     |   |
|      |                                                                 |   |
|      +------------------------------------------------------------------+   |
|                                                                             |
|   @After/Around后置 (后执行)                                                |
|                                                                             |
+-----------------------------------------------------------------------------+

执行顺序总结:

  1. LoggingAspect@Before
  2. SecurityAspect@Before
  3. 目标方法
  4. SecurityAspect@After / @AfterReturning
  5. LoggingAspect@After / @AfterReturning

代码示例

让我们创建两个切面并指定它们的顺序。

1. 安全切面 (优先级最高)

package com.example.aop;import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;@Aspect
@Component
@Order(1) // 优先级最高,数字最小
public class SecurityAspect {@Before("execution(* com.example.service.*.*(..))")public void checkSecurity() {System.out.println("--- [SecurityAspect @Order(1)]: Checking security... ---");}
}

2. 日志切面 (优先级较低)

package com.example.aop;import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;@Aspect
@Component
@Order(10) // 优先级较低,数字较大
public class LoggingAspect {@Before("execution(* com.example.service.*.*(..))")public void logBefore() {System.out.println("--- [LoggingAspect @Order(10)]: Logging before method execution... ---");}@After("execution(* com.example.service.*.*(..))")public void logAfter() {System.out.println("--- [LoggingAspect @Order(10)]: Logging after method execution... ---");}
}

3. 目标服务

package com.example.service;import org.springframework.stereotype.Service;@Service
public class MyService {public void doWork() {System.out.println("****** Executing core business logic in MyService.doWork() ******");}
}

4. 运行

当你调用 myService.doWork() 时,控制台的输出会是:

--- [SecurityAspect @Order(1)]: Checking security... ---
--- [LoggingAspect @Order(10)]: Logging before method execution... ---
****** Executing core business logic in MyService.doWork() ******
--- [LoggingAspect @Order(10)]: Logging after method execution... ---

结果分析:

  • Before 通知@Order(1)SecurityAspect 先于 @Order(10)LoggingAspect 执行。
  • After 通知:如果我们在 SecurityAspect 中也添加一个 @After 通知,那么它将会比 LoggingAspect@After 更晚执行,因为它在“洋葱”的最外层。

特殊情况:同一个切面内的通知顺序

如果多个不同类型的通知(@Before, @After 等)定义在同一个 @Aspect中,并且都匹配了同一个方法,它们的执行顺序是固定的,不受 @Order 注解影响

其执行顺序遵循标准的 AOP 流程:

  1. @Around (前置部分)
  2. @Before
  3. 目标方法
  4. @Around (后置部分)
  5. @After (最终通知)
  6. @AfterReturning (如果成功) 或 @AfterThrowing (如果异常)

注意:同一个切面内,多个相同类型的通知(例如两个 @Before 通知)的执行顺序是不确定的,你不应该依赖于它们的顺序。如果需要严格的顺序,应该将它们合并到一个通知方法中,或者拆分到不同的切面并通过 @Order 来控制。

总结

  • 使用 @Order(整数) 或实现 Ordered 接口来控制多个切面之间的执行顺序。
  • @Order值越小,优先级越高
  • 高优先级的切面像洋葱一样包裹低优先级的切面。
  • 这意味着高优先级切面的前置逻辑先执行后置逻辑后执行
  • 同一个切面内的通知顺序是固定的,无法通过 @Order 改变。
http://www.lqws.cn/news/518203.html

相关文章:

  • Android14音频子系统-Audio HAL分析
  • 南北差异之——跨端理解能力
  • sql格式化自动识别SQL语法结构
  • gsql: command not found
  • OpenLayers 上传Shapefile文件
  • 基于 Python 的批量文件重命名软件设计与实现
  • 智哪儿专访 | Matter中国提速:开放标准如何破局智能家居“生态孤岛”?
  • 舵机在智能家居里的应用
  • 第k个数字
  • 归并排序算法
  • 企业内部安全组网技术解析:安全通道选型、零信任架构与数据合规加密防护
  • 计算机网络-----详解HTTP协议
  • 基于springboot+vue的智慧农业专家远程指导系统
  • 苹果签名应用掉签频繁原因排查,以及如何避免
  • Mysql使用窗口函数查询
  • 左神算法之有序二维矩阵中的目标值查找
  • vscode管理go多个版本
  • 英飞凌高性能BMS解决方案助力汽车电动化
  • 【世纪龙科技】新能源汽车VR虚拟体验展示馆-解锁认知新维度
  • 灰度发布怎么保证数据库一致的
  • AES加密:为你的PDF文档加上一道钢铁防线
  • Kubernetes、Docker Swarm 与 Nomad 容器编排方案深度对比与选型指导
  • 论文阅读:A Survey on Large Language Models for Code Generation
  • 不用vue,只用html,即可简单实现electron项目
  • 鸿蒙OpenHarmony[Disassembler反汇编工具]ArkTS运编译工具链
  • IntelliJ IDEA 社区版安装终极教程(2025 最新图文详解)
  • 微信小程序中scss、ts、wxml
  • React19源码系列之 API (react)
  • 惠普HP Laser MFP 116w 打印机信息
  • 深度解析Lucene IndexWriter 性能优化