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

Spring 第四天:AOP 面向切面编程与声明式事务管理

前言Spring 有两大核心一个是前几天我们重点攻克的IoC/DI另一个就是今天要深入学习的AOP面向切面编程。还记得那句话吗“AOP 是在不改变原有代码的前提下对其进行功能增强”。听起来很神奇对吧今天我们就来揭开它神秘的面纱还会学到 AOP 最重要的实际应用——声明式事务管理。掌握了事务你的程序才能真正做到数据安全可靠。课前唠一唠你有没有遇到过这种场景——想在每个方法执行前后都加个日志或计时结果发现要改几十个地方今天学完 AOP你可以用几行代码就搞定这件事。你最想用 AOP 解决什么重复代码评论区许个愿说不定今天的案例就能帮你实现。一、AOP 简介1.1 什么是 AOPAOPAspect Oriented Programming面向切面编程是一种编程范式指导开发者如何组织程序结构。我们熟悉的OOP面向对象编程是另一种编程范式两者互为补充。1.2 AOP 的作用在不惊动原始设计的基础上为方法进行功能增强。说白了就是原来有一段代码已经写好了现在想给它加点功能比如打印日志、统计时间但又不想改原有代码AOP 就是干这个的。本质Spring AOP 底层采用的是代理模式后面我们会验证。1.3 AOP 核心概念我们来通过一个场景理解几个关键术语假设BookDaoImpl有save()、update()、delete()、select()四个方法。我们想给update和delete增加“计算万次执行时间”的功能但不改原代码。概念解释举例连接点JoinPoint程序执行过程中能插入增强的任意位置BookDaoImpl中的所有方法切入点Pointcut真正需要增强的方法匹配连接点的式子update()和delete()通知Advice抽取出来的共性功能要增强的内容“计算万次执行时间”的方法通知类定义通知的类MyAdvice类切面Aspect描述通知与切入点的对应关系“在update()和delete()上应用计时的通知”一句话记忆连接点是“地点”切入点是“我选中的地点”通知是“要干的事”切面是“在哪里干什么”。二、AOP 入门案例需求在方法执行前打印当前系统时间不改原代码。2.1 环境准备创建 Maven 项目添加spring-context依赖创建BookDao、BookDaoImpl、SpringConfig配置类和App运行类。项目结构如下src/main/java/com/itheima ├── config/SpringConfig ├── dao/BookDao (接口) ├── dao/impl/BookDaoImpl (实现类) └── App (运行类)2.2 AOP 实现步骤步骤 1导入 AOP 依赖dependencygroupIdorg.aspectj/groupIdartifactIdaspectjweaver/artifactIdversion1.9.4/version/dependency说明spring-context已包含spring-aop这里只需导入 AspectJ 的织入包。Spring 整合 AspectJ 是目前最常用的 AOP 开发方式。步骤 2定义通知类与通知ComponentAspect// 标识这是一个切面类publicclassMyAdvice{Pointcut(execution(void com.itheima.dao.BookDao.update()))privatevoidpt(){}// 切入点定义无参数、无返回值、方法体为空Before(pt())// 绑定通知到切入点在方法执行前运行publicvoidmethod(){System.out.println(System.currentTimeMillis());}}步骤 3在配置类上开启 AOP 注解功能ConfigurationComponentScan(com.itheima)EnableAspectJAutoProxy// 开启注解格式 AOP 功能publicclassSpringConfig{}关键注解速查EnableAspectJAutoProxy开启 AOP 注解支持Aspect声明切面类Pointcut定义切入点Before前置通知三、AOP 工作流程3.1 工作流程四步走Spring 容器启动加载需要增强的类和通知类此时 bean 还未创建读取切入点配置只读取被实际使用的切入点没被通知绑定的切入点忽略初始化 bean匹配切入点匹配失败 → 创建原始对象匹配成功 → 创建代理对象Proxy获取 bean 执行方法拿到的原始对象 → 直接调用拿到的代理对象 → 运行代理逻辑在原始方法前后插入增强3.2 验证容器中的对象是代理还是原始BookDaobookDaoctx.getBean(BookDao.class);System.out.println(bookDao.getClass());// 增强后打印的是代理类未增强是原始类⚠️注意不要直接用System.out.println(bookDao)因为toString()被重写过看不出区别。用getClass()才能看到真实类型。3.3 新增核心概念概念解释目标对象Target被代理的原始对象代理Proxy对目标对象增强后生成的对象包含原始方法 通知逻辑总结Spring AOP 的本质 代理模式。匹配切入点的方法会生成代理对象不匹配的就是原始对象。四、AOP 配置管理4.1 切入点表达式4.1.1 语法格式标准格式动作关键字(访问修饰符 返回值 包名.类/接口名.方法名(参数) 异常名)execution(publicUsercom.itheima.service.UserService.findById(int))// ↑访问修饰符 ↑返回值 ↑包名 ↑类名 ↑方法名 ↑参数访问修饰符、异常名可以省略写在接口上和写在实现类上都能匹配到调用接口最终走的还是实现类4.1.2 通配符符号含义示例*单个独立的任意符号execution(* com.*.service.*.find*(*))..多个连续的任意符号execution(* com..service.*.*(..))匹配子类类型*Service用得少了解即可4.1.3 书写技巧描述接口不描述实现类避免紧耦合访问修饰符通常省略接口方法都是public查询方法返回值用*增删改用精准类型包名尽量不用..用*做单级匹配接口名用*Service表示业务层模块方法名保留动词get、find名词用*实战套路业务层全部方法 →execution(* com.itheima.service.*Service.*(..))4.2 AOP 通知类型共 5 种通知类型下面通过一张图理解它们的位置方法执行流程 ┌─ 后置通知After成功/异常都执行 ─┐ 前置通知Before→ → 原始方法执行 → 返回后通知AfterReturning正常返回才执行 └─ 异常后通知AfterThrowing抛异常才执行 ─┘ 环绕通知Around 前置 后置能完全控制方法执行通知类型注解执行时机前置通知Before方法执行前后置通知After方法执行后无论是否异常返回后通知AfterReturning正常返回后异常后通知AfterThrowing抛出异常后环绕通知Around前后都可以最强大4.3 环绕通知详解重点环绕通知能实现其他所有通知类型的功能是实际开发中最常用的。Around(pt())publicObjectaround(ProceedingJoinPointpjp)throwsThrowable{System.out.println(around before advice ...);// 前置部分Objectretpjp.proceed();// 调用原始方法System.out.println(around after advice ...);// 后置部分returnret;}环绕通知注意事项重要必须依赖形参ProceedingJoinPoint否则无法调用原始方法如果不调用pjp.proceed()原始方法根本不会执行如果原始方法有返回值通知方法最好返回Object并把pjp.proceed()的返回值return出去原始方法无返回值时通知方法可设为void或Object必须处理Throwable异常⚠️坑点pjp.proceed()有两个重载版本。无参版本会自动传入原始参数有参版本pjp.proceed(args)可以修改参数后传入。后面案例会用到这个特性。4.4 AOP 通知获取数据4.4.1 获取参数非环绕通知在方法签名中加JoinPoint参数Before(pt())publicvoidbefore(JoinPointjp){Object[]argsjp.getArgs();System.out.println(Arrays.toString(args));}环绕通知用ProceedingJoinPoint它是JoinPoint的子类Around(pt())publicObjectaround(ProceedingJoinPointpjp)throwsThrowable{Object[]argspjp.getArgs();// 获取参数args[0]666;// 可以修改参数returnpjp.proceed(args);// 传入修改后的参数}4.4.2 获取返回值环绕通知直接接收pjp.proceed()的返回值返回后通知用returning属性AfterReturning(valuept(),returningret)publicvoidafterReturning(Objectret){System.out.println(afterReturning advice ...ret);}4.4.3 获取异常环绕通知用try-catch捕获抛出异常后通知用throwing属性AfterThrowing(valuept(),throwingt)publicvoidafterThrowing(Throwablet){System.out.println(afterThrowing advice ...t);}五、AOP 总结概念说明AOP 作用不惊动原代码为方法增强功能无侵入式本质代理模式生成代理对象切入点表达式中最实用写法execution(* com.xxx.service.*Service.*(..))最常用通知环绕通知Around环绕通知核心ProceedingJoinPoint.proceed()调用原始方法可获取数据参数getArgs()、返回值ret、异常try-catch六、AOP 事务管理重点事务是 AOP 最重要的实际应用场景。Spring 通过 AOP 实现了声明式事务管理让我们只需要一个注解就能搞定复杂的数据库事务。6.1 为什么需要事务转账案例分析场景Tom 给 Jerry 转账 100 元。Tom 账户减 100Jerry 账户加 100两个操作必须同时成功或同时失败。如果减钱成功、加钱失败100 块就凭空消失了。问题数据层每个操作都有自己独立的事务业务层的 transfer 方法没有事务出现异常时无法统一回滚。解决方案用 Spring 事务管理让 transfer 方法开启一个大事务把减钱和加钱两个操作纳入同一个事务中。6.2 Spring 事务管理三步走步骤 1在需要事务的方法上加TransactionalServicepublicclassAccountServiceImplimplementsAccountService{AutowiredprivateAccountDaoaccountDao;Transactionalpublicvoidtransfer(Stringout,Stringin,Doublemoney){accountDao.outMoney(out,money);// int i 1 / 0; // 出现异常事务会自动回滚accountDao.inMoney(in,money);}}步骤 2配置事务管理器JdbcConfig 类中BeanpublicPlatformTransactionManagertransactionManager(DataSourcedataSource){DataSourceTransactionManagermanagernewDataSourceTransactionManager();manager.setDataSource(dataSource);returnmanager;}因为 MyBatis 底层用的是 JDBC所以这里用DataSourceTransactionManager。步骤 3在配置类上开启事务注解ConfigurationComponentScan(com.itheima)PropertySource(classpath:jdbc.properties)Import({JdbcConfig.class,MybatisConfig.class})EnableTransactionManagement// 开启注解式事务publicclassSpringConfig{}关键注解速查Transactional声明方法需要事务管理EnableTransactionManagement开启事务注解支持6.3 事务角色角色说明对应事务管理员发起事务的一方业务层开启事务的方法如transfer事务协调员加入事务的一方数据层方法如outMoney、inMoney开启 Spring 事务后协调员的事务会加入到管理员的事务中形成一个整体。任何一个环节出异常整个事务都会回滚。6.4 事务属性Transactional有丰富的属性可配置属性作用示例readOnly只读事务查询用true增删改用falseTransactional(readOnly true)timeout超时时间秒-1 为永不超时Transactional(timeout -1)rollbackFor指定哪些异常回滚默认只回滚 RuntimeException 和 ErrorTransactional(rollbackFor {IOException.class})noRollbackFor指定哪些异常不回滚Transactional(noRollbackFor {NullPointerException.class})isolation事务隔离级别Transactional(isolation Isolation.DEFAULT)propagation事务传播行为Transactional(propagation Propagation.REQUIRES_NEW)⚠️重要Spring 默认只对RuntimeException和Error回滚。受检异常如IOException需要手动用rollbackFor指定才会回滚。6.5 事务传播行为Propagation场景转账操作中不管转账是否成功都需要记录日志。但日志操作不能因为转账失败而回滚。解决让日志方法用REQUIRES_NEW传播行为独立开启一个新事务。ServicepublicclassLogServiceImplimplementsLogService{AutowiredprivateLogDaologDao;Transactional(propagationPropagation.REQUIRES_NEW)publicvoidlog(Stringout,Stringin,Doublemoney){logDao.log(转账操作由out到in,金额money);}}传播行为管理员有事务管理员无事务REQUIRED默认加入管理员事务新建事务REQUIRES_NEW新建独立事务新建事务SUPPORTS加入管理员事务无事务运行NOT_SUPPORTED挂起管理员事务无事务运行无事务运行MANDATORY加入管理员事务报错NEVER报错无事务运行NESTED设置回滚点savePoint新建事务日常开发中REQUIRED默认能满足大部分需求REQUIRES_NEW用于像日志这种需要独立事务的场景。七、总结今天我们系统学习了 Spring 的第二个核心大模块——AOP 和声明式事务。模块核心要点AOP 核心概念连接点、切入点、通知、切面、目标对象、代理切入点表达式execution(* com.xxx.service.*Service.*(..))五种通知前置Before、后置After、返回后AfterReturning、异常后AfterThrowing、环绕Around数据获取参数getArgs()、返回值proceed()返回 /returning、异常try-catch/throwing事务管理Transactional 事务管理器 EnableTransactionManagement事务传播REQUIRED默认加入现有事务、REQUIRES_NEW始终新建事务结课小调查今天的内容量不小你最想在项目里试一试的是哪个A. 用环绕通知给所有 Service 方法加日志B. 用 AOP 统一处理参数空格C. 用Transactional管理数据库事务D. 写个独立的日志事务REQUIRES_NEW评论区告诉我你的选择也欢迎分享你在事务管理上踩过的坑我们一起避雷本文为 Spring Framework 第四天授课内容整理。AOP 和事务管理是 Spring 的精髓所在掌握了它们你的 Java 开发能力将迈上一个大台阶。如果觉得有帮助欢迎点赞、收藏、关注我们下节课见

相关文章:

Spring 第四天:AOP 面向切面编程与声明式事务管理

前言 Spring 有两大核心:一个是前几天我们重点攻克的 IoC/DI,另一个就是今天要深入学习的 AOP(面向切面编程)。 还记得那句话吗?“AOP 是在不改变原有代码的前提下对其进行功能增强”。听起来很神奇对吧?今…...

Groundhog:基于Git仓库的开发者时间自动追踪工具

1. 项目概述:一个面向开发者的时间管理利器如果你是一名开发者,或者你的工作与代码、项目、任务紧密相关,那么你一定对“时间都去哪儿了”这个问题深有感触。我们每天在各种编辑器、终端、浏览器标签页之间切换,处理着功能开发、B…...

CTO 每月烧 600 亿 token,3 个月完成百名程序员七八年写的 800 万行代码

①2026 年 5 月 9 日,昆仑万维董事长方汉的一番发言引热议,相关话题冲上热搜。方汉近日在访谈中坦承,自己每月实际消耗的 Token 高达 20 亿至 30 亿。此前他对外宣称的数字仅为 1 亿,属于刻意的低调处理。他甚至略带自嘲地表示&am…...

12,Springboot3+vue3实现系统公告功能

做一个新的公告模块步骤如下 一, 后端 1, 创建系统公告表 CREATE TABLE `notice` (`id` int NOT NULL AUTO_INCREMENT COMMENT 主键ID,`title` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT 公告标题,`content` varchar(255) COLLATE utf8mb4_unicode_ci …...

从DES到AES:被‘遗忘’的IDEA算法,它的设计思想给现代密码学留下了什么?

从DES到AES:被遗忘的IDEA算法如何塑造现代密码学 1991年诞生的IDEA算法曾被誉为"DES的完美继任者",却在历史舞台上悄然退场。当我们在讨论AES和椭圆曲线加密时,很少有人记得这个瑞士学者设计的算法如何影响了整个加密技术发展轨迹。…...

高精度电压基准技术:LT6657的创新与应用

1. 高精度电压基准的技术演进与系统需求在精密数据采集系统的设计中,电压基准如同整个系统的"心脏",其稳定性直接决定了测量结果的可靠性。过去二十年里,我参与过数十个工业测量项目,深刻体会到基准源选择对系统性能的致…...

别再傻傻切片了!PyTorch Tensor高级索引实战:用index_select、masked_select和gather提升数据处理效率

别再傻傻切片了!PyTorch Tensor高级索引实战:用index_select、masked_select和gather提升数据处理效率 在深度学习项目的日常开发中,数据处理环节往往占据了开发者大量的时间和精力。许多PyTorch用户习惯性地使用基础切片操作来处理Tensor数据…...

视频技术演进:从模拟到数字的革命与压缩技术解析

1. 视频技术演进:从模拟到数字的革命上世纪30年代末,当第一套视频标准在美国诞生时,谁也没想到这个被称为RS-170的技术会成为现代视频技术的基石。作为最早的模拟视频标准,RS-170定义了525线(其中480线为有效视频内容&…...

别再只用Matplotlib画图了!用Python这3个库(SciPy, NumPy, Scikit-learn)给你的数据曲线做个‘美容’

Python数据平滑三剑客:用Savitzky-Golay、插值与滑动平均打造专业级图表 当你面对满是噪点的折线图时,是否想过这些锯齿状的波动正在掩盖数据的真实故事?就像摄影师不会直接发布未经修饰的RAW格式照片,数据科学家也需要掌握图表美…...

第五篇:Spring事务管理——@Transactional的底层实现与失效场景

前言 在前面的文章中,我们拆解了Spring AOP的底层原理——动态代理和切面编程。现在,我们来看AOP最经典的应用:事务管理。 你每天用着Transactional,往Service方法上一加,事务就自动开启了。但面试中,事务是…...

AI代理协作平台agtx:用终端看板管理多AI编程工作流

1. 项目概述:一个能管理其他AI编程代理的终端看板如果你和我一样,每天要在Claude、Cursor、Codex这些AI编程工具之间来回切换,同时处理多个功能需求,那你肯定也经历过这种混乱:一个终端窗口里,Claude正在写…...

SQL与数据库开发(四):CASE WHEN 与“行转列/列转行”花式玩法

在企业级应用的开发中,后端程序员和报表工程师往往面临着一种天然的矛盾:“数据库的存储格式”与“前端的展示格式”是完全不匹配的。 关系型数据库最喜欢“瘦长”的表(不断往下插入新行),而业务方和老板最喜欢看的是…...

Linux系统编程-makefile文件与make命令的使用

目录 一.makefile文件 1.1什么是makefile 1.2 makefile的一、二、三 1.2.1 一个规则 (1) 两个基本原则: (2) 使用 ALL 来指定makefile的终极目标: 1.2.2 两个函数 (1) src $(wildcard *.c) (2) obj $(patsubst %.c, %.o, $(src)) 1.2.3 三个…...

AI Agent集成Kalshi预测市场交易技能:自动化交易与风险管理实战

1. 项目概述:一个为AI Agent设计的Kalshi预测市场交易技能如果你对量化交易、自动化脚本或者新兴的AI Agent生态感兴趣,并且听说过“预测市场”这个概念,那么今天聊的这个项目可能会让你眼前一亮。lacymorrow/openclaw-kalshi-trading-skill本…...

AI伦理编程实战:从公平性算法到可解释性模型的工程实践

1. 项目概述:当代码开始思考,我们该教它什么? “AI伦理编程”这个词,听起来像是一个技术乌托邦,一个我们只要遵循几条规则就能让机器变得善良的简单任务。但当你真正坐下来,试图将“公平”、“透明”、“无…...

机器学习在非洲公共卫生疾病预测中的实战应用与技术解析

1. 项目概述:当AI遇见非洲公共卫生在非洲大陆,公共卫生系统长期面临着资源不均、基础设施薄弱和疾病负担沉重的多重挑战。传统的疾病监测依赖于被动报告和人工数据分析,往往存在滞后性,当疫情警报拉响时,病毒可能已经悄…...

机器学习在非洲传染病预测与监测中的实战应用

1. 项目概述:当AI遇见非洲传染病防控在公共卫生领域,时间就是生命,资源就是防线。对于非洲大陆而言,这句话的分量尤为沉重。这里常年承受着全球最沉重的传染病负担,从水源性传播的霍乱、致命性极高的埃博拉&#xff0c…...

AI赋能风景园林设计:技术原理、实践案例与未来挑战

1. 项目概述:当AI遇见园林最近几年,我身边不少做景观设计的朋友,从最初的“AI能画图?试试看”,到现在的“这个参数化模型帮我省了一周工作量”,态度转变非常明显。这让我意识到,人工智能在风景园…...

AI赋能区域创新评估:融合记分板与政策文本分析的协同框架与实践

1. 项目概述与核心价值 最近在梳理区域创新政策与人工智能应用交叉领域的工作时,我深度实践了一个项目,核心是探讨如何将欧盟的“区域创新记分板”这套成熟的评估体系,与新兴的AI政策分析工具进行深度融合与协同应用。这听起来可能有些学术化…...

ARM Trace单元架构与TRCVICTLR寄存器详解

1. ARM Trace单元架构概述在嵌入式系统开发领域,调试能力往往决定了问题定位的效率和质量。ARM架构提供的Trace单元(Embedded Trace Macrocell, ETM)作为处理器指令执行流追踪的核心组件,已经成为现代SoC调试基础设施的重要组成部…...

使用 Python 快速接入 Taotoken 并调用多模型 API 的完整指南

🚀 告别海外账号与网络限制!稳定直连全球优质大模型,限时半价接入中。 👉 点击领取海量免费额度 使用 Python 快速接入 Taotoken 并调用多模型 API 的完整指南 对于希望快速集成大模型能力的 Python 开发者而言,逐一对…...

时序逻辑与值函数分解在强化学习中的应用

1. 时序逻辑与值函数分解的核心原理 时序逻辑(Temporal Logic, TL)作为形式化方法的重要分支,其本质是通过数学语言描述系统在时间维度上的行为约束。在控制理论与强化学习领域,TL的价值在于将复杂的任务需求转化为可计算的优化目…...

Arm架构DCU寄存器解析与安全调试实践

1. Arm生命周期管理器DCU寄存器深度解析 在Arm架构的嵌入式系统开发中,生命周期管理器(Lifecycle Manager, LCM)扮演着关键角色,而其中的调试控制单元(Debug Control Unit, DCU)寄存器组则是开发人员必须掌…...

ARM架构CNTP_CVAL寄存器详解与定时器编程实践

1. ARM架构中的CNTP_CVAL寄存器解析 在ARMv8/v9架构中,定时器系统是处理器关键的时间管理组件,而CNTP_CVAL(Counter-timer Physical Timer CompareValue Register)作为EL1物理定时器的比较值寄存器,在实时任务调度、中…...

AI 基本面量化:从理论到可部署 MVP-1.学习目标与工具链

AI 基本面量化实战:从理论到可部署 MVP 的完整学习路径1. 核心目标与 MVP 定义1.1 学习目标定位1.1.1 掌握 AI 技术与基本面分析深度融合的方法论体系AI 基本面量化的本质并非用复杂模型替代经典金融理论,而是以经济学逻辑为锚、以数据驱动为翼&#xff…...

物理 AI 为什么离不开边缘计算?

过去两年,AI 给人的印象基本是一回事——一个对话框,一个输入框。你打字它打字,你上传它分析,AI 安静地待在屏幕里,处理着一切关于文字、图像、代码的事情。行业的注意力也都跟着堆在那一头。云厂商抢算力,…...

3406硬核量化总结:黄大年茶思屋34期5题全解 重塑华为全球全栈技术霸权战略

华夏之光永存・硬核总结:黄大年茶思屋5题全解对华为战略的决定性价值 一、华为核心战略:全栈自主可控,构建端边云网芯一体化技术霸权 华为的核心战略是根技术全自研、全链路闭环、全场景覆盖,以芯片为底座、网络为联接、操作系统为中枢、AI为引擎、云为载体、行业应用为出…...

AI编程效率革命:Cursor Rules配置实战与团队协作指南

1. 项目概述:从“Cursor Rules”看现代开发者的效率革命最近在GitHub上看到一个名为usrrname/cursorrules的项目,这个标题乍一看有点意思,它直接点明了两个核心要素:cursor和rules。对于深度使用Cursor这款AI代码编辑器的开发者来…...

如何用python函数制作一个计算工具

大家好,这里是junlang的python文章 今天教大家如何用python函数做一个计算器,希望大家好好学习哦 如何制作 首先我们先定义4个函数,其中除法计算代码请看下面: def add (a,b,c):return (a b - c) def sub (x,y):return(x - y) def mulpl…...

星露谷物语模组加载器SMAPI:免费开源的游戏增强终极指南

星露谷物语模组加载器SMAPI:免费开源的游戏增强终极指南 【免费下载链接】SMAPI The modding API for Stardew Valley. 项目地址: https://gitcode.com/gh_mirrors/smap/SMAPI 星露谷物语模组加载器SMAPI是《星露谷物语》的官方模组API,为这款经典…...