多个切面的执行顺序

目录

📌 核心规则总结

🚀 详细执行流程(多个切面)

🔄 正常执行流程(无异常)

🚨 异常执行流程(目标方法抛出异常)

📊 关键点图示

� 常见陷阱与注意事项

🛠 如何控制顺序

💡 总结


在Spring AOP中,多个切面(Aspect)的执行顺序是一个需要特别注意的问题,尤其在涉及环绕通知(@Around)、前置/后置通知(@Before/@After)以及异常通知时。理解其规则对保证切面逻辑的正确性至关重要。

📌 核心规则总结

  1. 优先级(@Order 或 Ordered 接口):

    • 数值越小,优先级越高。

    • @Order(1) 的切面优先级高于 @Order(2) 的切面。

    • 未指定 @Order 的切面,其优先级是 Ordered.LOWEST_PRECEDENCE(即 Integer.MAX_VALUE,优先级最低)。

    • 实现 Ordered 接口并重写 getOrder() 方法可以达到与 @Order 注解相同的效果。

  2. 执行阶段:

    • "进入"目标方法阶段: 切面按 优先级从高到低 的顺序执行它们的 @Before 通知 和 @Around 通知中调用 proceed() 之前的部分

    • "退出"目标方法阶段: 切面按 优先级从低到高 的顺序执行它们的 @AfterReturning / @AfterThrowing / @After 通知 和 @Around 通知中调用 proceed() 之后的部分

  3. 通知类型内部顺序:

    • 同一个切面内的不同通知类型,执行顺序遵循AOP标准:

      • @Around(前置处理)→ @Before → 目标方法执行 → @Around(后置处理)→ @AfterReturning(正常返回)| @AfterThrowing(异常处理)→ @After(最终处理)

    • @After 通知总是在 @AfterReturning 或 @AfterThrowing 之前执行。 这有时会让人意外。

🚀 详细执行流程(多个切面)

假设你有两个切面:LoggingAspect (@Order(1)) 和 SecurityAspect (@Order(2)),它们都作用于同一个连接点(如某个Service方法)。

🔄 正常执行流程(无异常)

  1. 进入阶段(高优先级 -> 低优先级):

    • LoggingAspect @Around (开始部分 - 记录开始时间等)

    • LoggingAspect @Before

    • SecurityAspect @Around (开始部分 - 权限检查等)

    • SecurityAspect @Before

  2. 目标方法执行:

    • 实际的业务方法被调用执行。

  3. 退出阶段(低优先级 -> 高优先级):

    • SecurityAspect @After (清理资源等 - 注意这个先执行!)

    • SecurityAspect @AfterReturning (处理正常返回结果)

    • SecurityAspect @Around (结束部分 - 记录执行时间、处理返回值等)

    • LoggingAspect @After (清理资源等)

    • LoggingAspect @AfterReturning (记录返回值等)

    • LoggingAspect @Around (结束部分 - 记录总耗时等)

🚨 异常执行流程(目标方法抛出异常)

  1. 进入阶段(高优先级 -> 低优先级): (与正常流程相同)

    • LoggingAspect @Around (开始部分)

    • LoggingAspect @Before

    • SecurityAspect @Around (开始部分)

    • SecurityAspect @Before

  2. 目标方法执行: 抛出异常。

  3. 退出阶段(低优先级 -> 高优先级):

    • SecurityAspect @After (清理资源等 - 无论异常都执行)

    • SecurityAspect @AfterThrowing (处理捕获的异常)

    • SecurityAspect @Around (结束部分 - 如果捕获了异常,可以在这里处理或重新抛出)

    • LoggingAspect @After (清理资源等)

    • LoggingAspect @AfterThrowing (记录异常信息等)

    • LoggingAspect @Around (结束部分 - 如果捕获了异常,可以在这里处理或重新抛出)

    • 异常最终会传播给调用者(除非在某个通知中被捕获并处理掉)。

📊 关键点图示

[调用流程]

1. 进入阶段 (高优先级 -> 低优先级):
   [调用者]
     ↓
   [Logging @Around (start)] → [Logging @Before] → [Security @Around (start)] → [Security @Before]

2. 目标方法执行:
   [Security @Before] → [Target Method] ← [Security @Around (start)]

3. 退出阶段 (正常流程):
   [Target Method] → [Security @After] → [Security @AfterReturning] → [Security @Around (end)]
     ↓
   [Logging @After] ← [Logging @AfterReturning] ← [Logging @Around (end)]
     ↓
   [调用者 (正常返回)]

4. 退出阶段 (异常流程):
   [Target Method] → [Security @After] → [Security @AfterThrowing] → [Security @Around (end) - catch/handle]
     ↓
   [Logging @After] ← [Logging @AfterThrowing] ← [Logging @Around (end) - catch/handle]
     ↓
   [调用者 (收到异常)]

� 常见陷阱与注意事项

  1. @After 的执行时机: @After 通知总是在 @AfterReturning 或 @AfterThrowing 之前执行。这是由AOP代理的实现机制决定的。如果需要在 @AfterReturning 之后做一些事情,通常应该把逻辑放在 @AfterReturning 通知内部或 @Around 的结束部分。

  2. @Around 中的 proceed() @Around 通知必须调用 proceed() 来执行目标方法(或下一个切面/通知)。忘记调用 proceed() 会导致目标方法永远不会执行。proceed() 的返回值就是目标方法的返回值(或下一个切面修改后的返回值)。

  3. 异常处理: 如果在 @Around 通知中捕获了 proceed() 抛出的异常,并在通知内部处理掉(不重新抛出),那么 @AfterThrowing 通知将不会被触发,因为异常已经被"吃掉"了。调用者也不会收到异常。

  4. 未指定顺序: 如果多个切面都没有指定 @Order,它们的执行顺序是未定义的(取决于类加载顺序、Bean注册顺序等,不可靠)。强烈建议为所有切面显式指定 @Order

  5. 理解优先级数值: @Order(1) 优先级高于 @Order(2)。数值越小,优先级越高,越早执行"进入"部分,越晚执行"退出"部分。

  6. 切面本身也是Bean: 切面类本身是Spring管理的Bean。确保它们能被Spring正确扫描和实例化。复杂的Bean依赖或代理机制也可能间接影响顺序(显式使用 @Order 是最可靠的方式)。

🛠 如何控制顺序

  1. 使用 @Order 注解: 这是最推荐、最常用的方式。直接在切面类上标注 @Order(value)

    @Aspect
    @Component
    @Order(1)  // 高优先级切面
    public class LoggingAspect { ... }
    
    @Aspect
    @Component
    @Order(2)  // 低优先级切面  
    public class SecurityAspect { ... }
    

  2. 实现 Ordered 接口: 让切面类实现 org.springframework.core.Ordered 接口,并重写 getOrder() 方法。

    @Aspect
    @Component
    public class TransactionAspect implements Ordered {
        @Override
        public int getOrder() {
            return 0; // 设置为最高优先级
        }
        // ... 其他通知方法 ...
    }
    

  3. 在Spring Boot中使用 @AutoConfigureAfter (较少用): 主要用于自动配置类之间的顺序,不常用于普通业务切面。

💡 总结

掌握Spring AOP切面执行顺序的关键在于:

  1. @Order 决定切面优先级: 数值越小,优先级越高。

  2. "进入"顺序: 高优先级 -> 低优先级 (@Before@Around前半部分)。

  3. "退出"顺序: 低优先级 -> 高优先级 (@After@AfterReturning/@AfterThrowing@Around后半部分)。

  4. @After 总是先于 @AfterReturning/@AfterThrowing 执行。

  5. 务必显式指定 @Order 以避免不可预测的行为。

通过合理设置 @Order 值并深刻理解上述流程,你可以精确控制多个切面的协作逻辑,确保事务、日志、安全、缓存等横切关注点按预期顺序生效。 💪

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值