博主社群介绍: ① 群内初中生、高中生、本科生、研究生、博士生遍布,可互相学习,交流困惑。
② 热榜top10的常客也在群里,也有数不清的万粉大佬,可以交流写作技巧,上榜经验,涨粉秘籍。
③ 群内也有职场精英,大厂大佬,跨国企业主管,可交流技术、面试、找工作的经验。
进群免费赠送写作秘籍一份,助你由写作小白晋升为创作大佬,进群赠送CSDN评论防封脚本,送真活跃粉丝,助你提升文章热度。
群公告里还有全网大赛约稿汇总/博客提效工具集/CSDN自动化运营脚本 有兴趣的加文末联系方式,备注自己的CSDN昵称,拉你进群,互相学习共同进步。

img


Spring Boot AOP (四)与事务、异常处理交互

1. 引言

在企业项目中,AOP 不仅用于日志和性能监控,还与 事务管理异常处理 密切相关。理解 AOP、事务、异常三者的执行顺序 对架构设计和问题排查至关重要。

Spring 事务是通过 AOP 代理实现的,@Transactional 注解会生成一个事务切面,织入目标方法。


2. @Transactional 与 AOP 结合

2.1 核心机制

  1. @Transactional 注解会被 TransactionInterceptor 处理
  2. Spring 使用 环绕通知(Around Advice)在方法调用前开启事务,方法执行后提交或回滚事务
  3. 如果目标方法抛出异常,事务回滚策略生效

2.2 示例代码

@Service
public class UserService {

    @Transactional
    public void createUser(String name) {
        System.out.println("创建用户: " + name);
        if (name.equals("error")) {
            throw new RuntimeException("模拟异常");
        }
    }
}
@Aspect
@Component
public class LoggingAspect {

    @Before("execution(* com.example.service..*.*(..))")
    public void logBefore(JoinPoint jp) {
        System.out.println("日志前置: " + jp.getSignature());
    }

    @AfterReturning("execution(* com.example.service..*.*(..))")
    public void logAfter(JoinPoint jp) {
        System.out.println("日志后置: " + jp.getSignature());
    }
}

3. AOP 与事务执行顺序

切面 类型 执行时机
LoggingAspect @Before 方法执行前
TransactionInterceptor @Around 方法执行前开启事务
目标方法 - 执行业务逻辑
TransactionInterceptor @Around 方法执行后提交或回滚事务
LoggingAspect @AfterReturning / @AfterThrowing 方法返回后执行日志/异常记录

Mermaid 流程图:AOP + 事务 + 异常

flowchart TD
    A[方法调用] --> B[LoggingAspect @Before]
    B --> C[TransactionInterceptor @Around 前开启事务]
    C --> D[执行目标方法]
    D -->|正常返回| E[TransactionInterceptor 提交事务]
    D -->|异常抛出| F[TransactionInterceptor 回滚事务]
    E --> G[LoggingAspect @AfterReturning]
    F --> H[LoggingAspect @AfterThrowing]
    G --> I[返回客户端]
    H --> I

4. 异常通知与事务交互

4.1 异常通知触发条件

  • @AfterThrowing 仅在目标方法抛出异常时执行
  • @AfterReturning 仅在方法正常返回时执行
  • @After 无论成功或异常都会执行

4.2 示例

@Aspect
@Component
public class ExceptionAspect {

    @AfterThrowing(pointcut = "execution(* com.example.service..*.*(..))", throwing = "ex")
    public void logException(JoinPoint jp, Throwable ex) {
        System.out.println("捕获异常: " + ex.getMessage() + " 方法: " + jp.getSignature());
    }
}

5. 方法调用顺序示意图

Client Proxy TransactionInterceptor LoggingAspect Target 调用 createUser("Tom") @Before 开启事务 执行目标方法 返回/异常 提交或回滚事务 @AfterReturning / @AfterThrowing 返回结果 Client Proxy TransactionInterceptor LoggingAspect Target

6. 多切面 + 异常 + 事务组合

@Aspect
@Component
@Order(1)
public class LoggingAspect {
    @Before("execution(* com.example.service..*.*(..))")
    public void before(JoinPoint jp) { System.out.println("日志前置"); }
}

@Aspect
@Component
@Order(2)
public class TransactionAspect {
    @Around("execution(* com.example.service..*.*(..))")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("事务开始");
        try {
            Object result = pjp.proceed();
            System.out.println("事务提交");
            return result;
        } catch (Throwable ex) {
            System.out.println("事务回滚");
            throw ex;
        }
    }
}

@Aspect
@Component
@Order(3)
public class MetricsAspect {
    @AfterReturning("execution(* com.example.service..*.*(..))")
    public void afterReturning(JoinPoint jp) { System.out.println("性能监控"); }
}

执行顺序示意

flowchart TD
    A[方法调用] --> B[LoggingAspect @Before]
    B --> C[TransactionAspect @Around 前]
    C --> D[目标方法执行]
    D -->|正常| E[TransactionAspect 提交事务]
    D -->|异常| F[TransactionAspect 回滚事务]
    E --> G[MetricsAspect @AfterReturning]
    F --> H[异常处理切面执行]
    G --> I[返回客户端]
    H --> I

7. 小结

  • Spring 事务基于 AOP 环绕通知实现
  • 异常通知和事务回滚紧密关联
  • 多切面情况下,通知顺序由 @OrderOrdered 控制
  • Mermaid 图直观展示了 多切面 + 事务 + 异常 的方法调用链
  • 理解这个顺序有助于正确设计日志、事务、异常切面,避免回滚异常被切面吞掉或日志记录错位

结束语


👨‍💻 关于我

持续学习 | 追求真我

如果本篇文章帮到了你 不妨点个赞吧~ 我会很高兴的。想看更多 那就点个关注吧 我会尽力带来有趣的内容 😎。

感谢订阅专栏 三连文章

image-20251011155556997

掘金点击访问Qiuner CSDN点击访问Qiuner GitHub点击访问Qiuner Gitee点击访问Qiuner

专栏 简介
📊 一图读懂系列 图文并茂,轻松理解复杂概念
📝 一文读懂系列 深入浅出,全面解析技术要点
🌟持续更新 保持学习,不断进步
🎯 人生经验 经验分享,共同成长

你好,我是Qiuner. 为帮助别人少走弯路而写博客

如果本篇文章帮到了你 不妨点个吧~ 我会很高兴的 😄 (^ ~ ^) 。想看更多 那就点个关注吧 我会尽力带来有趣的内容 😎。

代码都在Github或Gitee上,如有需要可以去上面自行下载。记得给我点星星哦😍

如果你遇到了问题,自己没法解决,可以去我掘金评论区问。CSDN评论区和私信消息看不完 掘金消息少一点.

上一篇推荐 链接
Java程序员快又扎实的学习路线 点击该处自动跳转查看哦
一文读懂 AI 点击该处自动跳转查看哦
一文读懂 服务器 点击该处自动跳转查看哦
2024年创作回顾 点击该处自动跳转查看哦
一文读懂 ESLint配置 点击该处自动跳转查看哦
老鸟如何追求快捷操作电脑 点击该处自动跳转查看哦
未来会写什么文章? 预告链接
一文读懂 XX? 点击该处自动跳转查看哦
2025年终总结 点击该处自动跳转查看哦
一图读懂 XX? 点击该处自动跳转查看哦

img

Logo

助力广东及东莞地区开发者,代码托管、在线学习与竞赛、技术交流与分享、资源共享、职业发展,成为松山湖开发者首选的工作与学习平台

更多推荐