关于aop 执行顺序问题

本文探讨了在Spring框架中,自定义注解与@Transactional事务管理注解的执行顺序问题。当自定义注解未指定@Order时,其执行顺序可能晚于@Transactional,导致异常捕获而事务无法回滚。解决方法是在自定义注解中添加@Order以明确执行顺序。同时,若两个未指定@Order的切面,它们的执行顺序会依据切面方法名决定。了解这一机制对于优化事务管理和错误处理至关重要。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

今天偶然发现@注解执行顺序引发一轮探究

问题是 业务代码自定义注解 优先于 @transactional 事务执行,异常被捕捉导致 事务无法回滚

先看下@transactional 执行顺序

@EnableTransactionManagement 注解源码里默认顺序是Oanrdered.LOWEST_PRECEDENCE

按照 执行顺序先进后出的原则 应该在自定义注解逻辑执行完毕之前提交事务,

最后原因发现 自定义注解 未加上@order 字段,所以未加@order注解的 都是在 定义@order 切面后去 执行,

 如果2个切面都未打上@order注解,他的执行顺序 按照切面 方法名比较大小来确定执行顺序?

### AOP通知类型的执行顺序AOP(面向切面编程)中,不同的通知类型具有特定的执行顺序。以下是关于这些通知类型及其执行顺序的具体解释: #### 1. **前置通知 (@Before)** 前置通知会在目标方法执行之前运行。它主要用于在方法调用前添加额外的功能逻辑。如果程序正常执行,则此通知会先于其他任何通知被执行[^3]。 ```java @Before("pt()") public void before() { System.out.println("Executing Before Advice"); } ``` #### 2. **环绕通知 (@Around)** 环绕通知是最强大的一种通知类型,它可以控制目标方法的执行流程。环绕通知可以在目标方法执行前后都进行操作,并且可以选择是否继续执行目标方法。它的优先级通常高于 `@Before` `@AfterReturning` 的默认行为,但在实际项目中可以通过配置调整其相对位置[^4]。 ```java @Around("pt()") public Object around(ProceedingJoinPoint joinPoint) throws Throwable { System.out.println("Executing Around Advice (Before)"); Object result = joinPoint.proceed(); // 调用目标方法 System.out.println("Executing Around Advice (After)"); return result; } ``` #### 3. **返回通知 (@AfterReturning)** 当目标方法成功执行并返回结果时,返回通知会被触发。这种通知适用于记录日志或其他依赖于方法返回值的操作。需要注意的是,只有当目标方法未抛出异常的情况下才会执行该通知。 ```java @AfterReturning(pointcut="pt()", returning="retVal") public void afterReturning(Object retVal) { System.out.println("Method returned value: " + retVal); } ``` #### 4. **后置最终通知 (@After)** 无论目标方法是否发生异常,后置最终通知都会被执行。因此,它是清理资源的理想场所之一。即使有异常被捕获或处理完毕,这个通知仍然有效[^2]。 ```java @After("pt()") public void after() { System.out.println("Executing After Advice (Always executed)"); } ``` #### 5. **异常通知 (@AfterThrowing)** 当目标方法抛出了指定类型的异常时,异常通知就会被激活。这使得开发者能够集中管理错误场景下的响应措施。 ```java @AfterThrowing(pointcut="pt()", throwing="ex") public void afterThrowing(Exception ex) { System.out.println("Exception thrown: " + ex.getMessage()); } ``` --- #### 综合执行顺序总结 假设存在多种通知类型应用于同一连接点上,那么它们的标准执行顺序如下所示: 1. 环绕通知 (`@Around`) —— 如果允许则进入下一步; 2. 前置通知 (`@Before`); 3. 目标方法本身; - 若无异常: 1. 返回通知 (`@AfterReturning`) 2. 后置最终通知 (`@After`) - 若有异常: 1. 异常通知 (`@AfterThrowing`) 2. 后置最终通知 (`@After`) 上述规则基于标准情况得出结论,而具体实现可能因框架版本差异略有区别。 --- ### 示例代码展示完整的执行过程 下面是一个综合示例来演示各种通知的实际效果: ```java @Component @Aspect public class LoggingAspect { @Pointcut("execution(* com.example.service.*.*(..))") public void serviceMethods() {} @Before("serviceMethods()") public void logBefore() { System.out.println("[Before] Method is about to execute."); } @AfterReturning(value = "serviceMethods()", returning = "result") public void logReturn(Object result) { System.out.println("[AfterReturning] Method has finished with result: " + result); } @AfterThrowing(value = "serviceMethods()", throwing = "error") public void logError(Throwable error) { System.out.println("[AfterThrowing] An exception occurred: " + error.getMessage()); } @After("serviceMethods()") public void logFinally() { System.out.println("[After] This will always run regardless of exceptions or results."); } @Around("serviceMethods()") public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable { System.out.println("[Around-Before] Entering method..."); try { Object proceed = joinPoint.proceed(); System.out.println("[Around-After] Exiting method..."); return proceed; } catch (Throwable throwable) { System.err.println("[Around-Catch] Exception caught!"); throw throwable; // Re-throws the exception so other advices can handle it. } } } ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值