7、Spring_AOP
一、Spring AOP 简介
1.概述
-
对于spring来说,有三大组件,IOC,ID,AOP
-
aop概述:AOP(Aspect Oriented Programming)面向切面编程。
-
作用:不改变原有代码设计的基础上实现功能增强
-
例子
-
传统打印日志
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YVTRWA8Z-1692777970686)(picture/image-20221103171648609.png)]](https://img-blog.csdnimg.cn/6cb819ecef3240bb9a0d385b5d4e8394.png)
-
使用AOP增强之后
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-scLGJ5cf-1692777970687)(picture/image-20221103171749982.png)]](https://img-blog.csdnimg.cn/e342104d43954efda73aa9b52008dd77.png)
-
-
2.代理模式
- 如果没有听过代理模式,点击链接先学习代理模式 : https://www.bilibili.com/video/BV1tY411Z799/?share_source=copy_web&vd_source=fdccda7d1272a2e0f49cadca354a5073
- 静态代理
- 动态代理
- jdk 动态代理
- cglib 动态代理
二、AOP概念
1.案例分析
-
创建类提供增删改查方法,实现事务增强操作功能
public interface IStudentService {void save(Student student);int update(Student student);Student queryStudentById(Long id); } -
接口实现类
public class StudentServiceImpl implements IStudentService {public void save(Student student) { // System.out.println("开启事务");System.out.println("保存操作"); // System.out.println("关闭事务");}public int update(Student student) { // System.out.println("开启事务");System.out.println("更新操作"); // System.out.println("关闭事务");return 0;}public Student queryStudentById(Long id) {System.out.println("查询操作");return null;} } -
提供通知类
public class TransactionAdvice {public void before(){System.out.println("开启事务");}public void after(){System.out.println("关闭事务");}public void invoke(){before();//具体的业务执行after();} }
2.核心概念
2.1概念
- 连接点(JoinPoint):对于需要增强的方法就是连接点
- 切入点(Pointcut):需要增强的方法是切入点,匹配连接点的式子
- 通知(Advice):存放需要增强功能的共性代码,就叫通知
- 切面(Aspect):通知是需要增强的功能存在多个,切入点是需要增强的方法也存在多个,需要去给切入点和通知做关联,知道哪个切入点对应哪个通知,这种描述关系就叫切面
- 通知类:存放通知(方法)的类
2.2图示
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-o1PL1Rii-1692777970688)(picture/image-20221103181229013.png)]](https://img-blog.csdnimg.cn/1bc3d5addaa141899c7355d3d002f539.png)
3.核心概念
- 目标对象 target
- 代理 proxy
三、通过注解实现AOP配置
1.导入依赖
-
导入aop依赖
<dependency><groupId>org.springframework</groupId><artifactId>spring-aspects</artifactId><version>5.2.17.RELEASE</version> </dependency> -
导入Spring依赖
<dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.2.17.RELEASE</version> </dependency>
2.配置AOP支持
-
@EnableAspectJAutoProxy
-
说明
名称 @EnableAspectJAutoProxy 使用位置 配置类上 作用 开启注解的aop支持 -
代码
@Configuration @EnableAspectJAutoProxy @ComponentScan("cn.sycoder") public class AppConfig { }
3.创建切面类
-
@Aspect
-
说明
名称 @Aspect 作用 设置当前类为切面类 使用位置 类上 属性 String value() default “”;可以给切面指定名称 -
@Pointcut
-
说明
名称 @Pointcut 作用 设置切入点方法 使用位置 方法上 属性 String value() default “”;切入点表达式 -
代码
@Component @Aspect public class TransactionAdvice {//定义通知 绑定切点和通知的关系@Before("pc()")public void before(){System.out.println("开启事务");}@After("pc()")public void after(){System.out.println("关闭事务");}//定义切点@Pointcut("execution(void cn.sycoder.service.impl.StudentServiceImpl.save(..))")public void pc(){} }
4.测试aop
-
测试代码
@Testpublic void testAop(){AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);IStudentService bean = applicationContext.getBean(IStudentService.class);bean.save(null);}-
打印输出
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Q9xF3fAI-1692777970689)(picture/image-20221103205153372.png)]](https://img-blog.csdnimg.cn/abcbd9ce07c849b79c1606f753e69ae0.png)
-
5.各种通知
5.1@Before
-
前置通知:被代理的目标方法执行前执行
-
说明
名称 @Before 使用位置 方法上 作用 前置通知,目标方法执行前执行 属性 String value(); 切入点表达式 可以提供的入参 JoinPoint joinPoint ,切点 -
使用
@Before("execution(void cn.sycoder.service.impl.StudentServiceImpl.save(..))") public void before(JoinPoint joinPoint){System.out.println("开启事务"); }
5.2@After
-
后置通知:被代理的目标方法执行后执行
-
说明
名称 @After 使用位置 方法上 作用 后置通知:被代理的目标方法执行后执行 属性 String value(); 切入点表达式 可以提供的入参 JoinPoint joinPoint ,切点 -
使用
@After("execution(void cn.sycoder.service.impl.StudentServiceImpl.save(..))") public void after(){System.out.println("关闭事务"); }
5.3@AfterReturning
-
返回通知:被代理的目标方法成功结束后执行
-
说明
名称 @AfterReturning 使用位置 方法上 作用 返回通知:被代理的目标方法成功结束后执行 属性 String value(); 切入点表达式,String returning();方法返回值 可以提供的入参 JoinPoint joinPoint ,切点,方法返回值 obj -
使用
- 如果想要得到返回值,需要在注解上添加参数returning名称,对应方法参数名称
- 切面表达式的返回值为*而不是void
@AfterReturning(returning = "obj",value = "execution(* cn.sycoder.service.impl.StudentServiceImpl.update(..))") public void afterReturning(JoinPoint joinPoint,Object obj){System.out.println(obj);System.out.println("返回通知"); }
5.4@AfterThrowing
-
异常通知:被代理的目标方法出现异常后执行
-
说明
名称 @AfterThrowing 使用位置 方法上 作用 异常通知:被代理的目标方法出现异常后执行 属性 String value(); 切入点表达式String throwing();异常返回 可以提供的入参 JoinPoint joinPoint ,切点,异常返回值 th -
使用
@AfterThrowing(throwing = "th",value = "execution(void cn.sycoder.service.impl.StudentServiceImpl.save(..))") public void afterThrowing(JoinPoint pointcut,Throwable th){System.out.println("异常通知"); }
5.5@Around
-
环绕通知:可以使用 try 代码块把被代理的目标方法围绕住,就可以做自己想做的操作,可以在里面做任何的操作
-
说明
名称 @Around 使用位置 方法上 作用 异常通知:被代理的目标方法出现异常后执行 属性 String value(); 切入点表达式 可以提供的入参 ProceedingJoinPoint joinPoint,可以通过该对象调用原始方法 -
使用
@Around("execution(void cn.sycoder.service.impl.StudentServiceImpl.save(..))")public void around(ProceedingJoinPoint joinPoint){try{System.out.println("前置通知");Object proceed = joinPoint.proceed();//执行目标方法System.out.println("返回通知");}catch (Exception e){e.printStackTrace();} catch (Throwable throwable) {System.out.println("异常通知");throwable.printStackTrace();} finally {}}
5.6各种通知执行顺序
- 环绕通知—前置通知—目标方法—返回通知或异常通知—后置通知
6.切入点表达式
-
概述:切入点表达式是用来寻找目标代理方法的
execution(public void cn.sycoder.service.impl.StudentServiceImpl.save(..)) -
图示
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZrwcESLt-1692780385498)(picture/image-20221104150052284.png)]](https://img-blog.csdnimg.cn/4d68f01675c04342915a313d9dc745e7.png)
-
表达式实操
编号 名称 使用位置 作用 1 * 代替权限修饰符和返回值 表示任意权限和返回 2 * 使用到包位置 一个*表示当前一层的任意 3 *… 使用到包位置 任意包任意类 4 * 使用到类 表示任意类 5 *Service 使用到类 表示寻找以Service 结尾的任意接口或类 6 … 使用到参数 表示任意参数 -
案例:找到实现类中的任意save方法
execution(* cn.sycoder.service.impl.StudentServiceImpl.save(..)) -
案例:sycoder 包下面的类中的任意update 方法
execution(* cn.sycoder.*.update(..)) -
案例:找到sycoder 包下面及其任意子包中的任意update 方法
execution(* cn.sycoder.*..update(..)) -
案例:找到service 下面任意类的update 方法
execution(* cn.sycoder.service.*.update(..)) -
案例:找到以Service 结尾的接口或者类的update 方法
execution(* cn.sycoder.service.*Service.update(..)) -
案例:找到Service 结尾的接口或者类的update 方法,任意参数的
execution(* cn.sycoder.service.*Service.update(..))
-
-
注意:如果你切的越模糊,那性能就会越低,所以实际开发中,建议把范围切小一点
-
优先级
- 如果想手动指定优先级关系,可以使用@Order(1)注解
- 提供的值越小,优先级越高
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wdsnfMJz-1692780385499)(picture/image-20221104155839835.png)]](https://img-blog.csdnimg.cn/1f02377ac394475fb7aed95d847f94d7.png)
- 如果想手动指定优先级关系,可以使用@Order(1)注解
-
重用切入点表达式
-
定义切点
@Component @Aspect public class TransactionAdvice {//定义切点@Pointcut("execution(public void cn.sycoder.service.impl.StudentServiceImpl.save(..))")public void pc(){System.out.println("----切点");} } -
在其他切面类通知里面重用切点
@Component @Aspect public class LogAdvice {@Before("cn.sycoder.advice.TransactionAdvice.pc()")public void log(){System.out.println("-0-----这里是打印日志");} } -
切面内部自己重用
@Component @Aspect public class TransactionAdvice {//定义切点@Pointcut("execution(public void cn.sycoder.service.impl.StudentServiceImpl.save(..))")public void pc(){System.out.println("----切点");}//定义通知 绑定切点和通知的关系//前置通知@Before("pc()")public void before(JoinPoint joinPoint){String name = joinPoint.getSignature().getName();System.out.println(name);System.out.println("开启事务");}
-
7.获取通知相关信息
-
获取连接点信息,在通知方法中添加参数 JoinPoint 即可
@Before("pc()") public void before(JoinPoint joinPoint){String name = joinPoint.getSignature().getName();System.out.println(name);System.out.println("开启事务"); } -
获取目标方法返回值
- 使用AfterReturning 中的 returning 属性,这里指定的名称即是我们方法传入的名称
@AfterReturning(returning = "obj",value = "pc()")public void afterReturning(JoinPoint joinPoint,Object obj){System.out.println(obj);System.out.println("返回通知");} -
获取异常
- 使用AfterThrowing 中的 throwing 属性,这里指定的名称即是我们方法传入的参数名称
@AfterThrowing(throwing = "th",value = "execution(* cn.sycoder.service.impl.StudentServiceImpl.save(..))")public void afterThrowing(JoinPoint pointcut,Throwable th){System.out.println("异常通知");} -
如果使用环绕通知
- 使用ProceedingJoinPoint joinPoint
@Around("execution(void cn.sycoder.service.*..save(..))")public void around(ProceedingJoinPoint joinPoint){try{System.out.println("环绕通知"); // System.out.println("前置通知");Object proceed = joinPoint.proceed();//执行目标方法 // System.out.println("返回通知");}catch (Exception e){e.printStackTrace();} catch (Throwable throwable) { // System.out.println("异常通知");throwable.printStackTrace();} finally {}}
四、XML配置AOP
1.导入依赖
<dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.2.17.RELEASE</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-aspects</artifactId><version>5.2.17.RELEASE</version></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><!-- <scope>test</scope>--></dependency>
2.基本准备
-
创建 service 接口以及方法
public interface IStudentService {void save(Student student); }public class StudentServiceImpl implements IStudentService {public void save(Student student) {System.out.println("保存操作");} } -
创建切面类
public class XmlAspect {public void before(){System.out.println("前置通知");}public void pointCut(){}public void after(JoinPoint joinPoint){System.out.println("后置通知");}public void afterReturning(Object obj){System.out.println("返回通知"+obj);}public void afterThrowing(Throwable t){System.out.println("异常通知");} }
3.创建xml 配置文件
-
aop.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd"><bean id="service" class="cn.sycoder.service.impl.StudentServiceImpl"></bean><bean id="xmlAspect" class="cn.sycoder.aspect.XmlAspect"></bean><aop:aspectj-autoproxy/><aop:config> <!-- 配置切面类--><aop:aspect ref="xmlAspect"> <!-- 配置切点--><aop:pointcut id="pc" expression="execution(* cn.sycoder.service.*..*(..))"/> <!-- 配置前置通知--><aop:before method="before" pointcut-ref="pc"></aop:before> <!-- 配置后置通知--><aop:after method="after" pointcut-ref="pc"></aop:after> <!-- 配置返回通知--><aop:after-returning method="afterReturning" returning="obj" pointcut-ref="pc"></aop:after-returning> <!-- 异常通知--><aop:after-throwing method="afterThrowing" throwing="t" pointcut-ref="pc"></aop:after-throwing></aop:aspect></aop:config> </beans>
4.总结
- 以后在公司使用注解的方式最流行,所以,xml 配置作为了解内容即可
相关文章:
7、Spring_AOP
一、Spring AOP 简介 1.概述 对于spring来说,有三大组件,IOC,ID,AOP aop概述:AOP(Aspect Oriented Programming)面向切面编程。 作用:不改变原有代码设计的基础上实现功能增强 例子 传统打印日志 使用…...
QChart:数据可视化(用图像形式显示数据内容)
1、数据可视化的图形有:柱状/线状/条形/面积/饼/点图、仪表盘、走势图,弦图、金字塔、预测曲线图、关系图、数学公式图、行政地图、GIS地图等。 2、在QT Creator的主页面,点击 欢迎》示例》右侧输入框 输入Chart,即可查看到QChar…...
【python】Leetcode(primer-set)
文章目录 78. 子集(集合的所有子集)90. 子集 II(集合的所有子集) 更多 leetcode 题解可参考:【Programming】 78. 子集(集合的所有子集) 给定一组不含重复元素的整数数组 nums,返回…...
【LVS集群】
目录 一、集群概述 1.负载均衡技术类型 2.负载均衡实现方式 二、LVS结构 1.三层结构 2.架构对象 三、LVS工作模式 四、LVS负载均衡算法 1.静态负载均衡 2.动态负载均衡 五、ipvsadm命令详解 1. -A 2. -D 3. -L 4. -a 5. -d 6. -l 7. -t 8. -s 9. -r 10. -…...
软考高级系统架构设计师系列之:论文题目类型、论文考试大纲、历年考试论文真题汇总、论文写作原则、论文写作常见问题、论文评分标准
软考高级系统架构设计师系列之:论文题目类型、论文考试大纲、历年考试论文真题汇总、论文写作原则、论文写作常见问题、论文评分标准 一、论文写作概述二、论文题目类型三、论文考试大纲1.系统建模2.软件架构设计3.系统设计4.分布式系统设计5.系统的可靠性分析与设计6.系统的安…...
完整的application.xml
<!-- 资源文件配置 --><beans profile"dev"><bean class"com.ningpai.util.CustomPropertyPlaceholderConfigurer"><property name"locations"><list><value>classpath:/com/ningpai/web/config/dev/jdbc.p…...
C语言:运算符优先级
一、优先级(常使用的运算符) 见表格 二、注意 总体原则:算术运算符 > 关系运算符 > 逻辑运算符 > 赋值运算符 同一级别下的运算符的运算次序由表达式的结合方向决定 运算符注释级别( )圆括号1[ ]数组下标1后置后置2后置--后置--2前置…...
Android GreenDao数据库升级(附Demo)
前言 大家好久不见,一转眼马上八月份下旬了,最近由于工作比较忙,没时间给大家更新博文。百忙之中抽出时间,给大家来更新一篇关于GreenDao3数据库的升级。 关于GreenDao的详细介绍以及一些逻辑性的增、删、改、查等,可以…...
剑指 Offer 32 - III. 从上到下打印二叉树 III
目录 使用函数实现 使用双端队列实现 请实现一个函数按照之字形顺序打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右到左的顺序打印,第三行再按照从左到右的顺序打印,其他行以此类推。 例如: 给定二叉树: [3,9,20,nu…...
【QT5-自我学习-线程qThread移植与使用-通过代码完成自己需要功能-移植小记3】
【QT5-自我学习-线程qThread移植与使用-通过代码完成自己需要功能-移植小记3】 1、前言2、实验环境3、自我总结(1)文件的编写(2)信号与槽的新理解(3)线程数据的传递 4、移植步骤第一步:添加新文…...
后端开发12.商品模块
概述 简介 商品模块这个设计的非常复杂 效果图 数据库...
/usr/bin/containerd: Operation not permitted
问题 今天在重启docker程序的时候一直启动不起来,通过systemctl status docker和jourctl -xu docker也没有发现什么有用的报错信息,无奈只好查看/var/log/message,发现以下错误提示: Started containerd container runtime Start…...
分析商务报表使用什么工具?
传统的BI分析商务报表存在的问题 随着数字化转型的深入推进,企业面临着海量数据的挑战和机遇。数据是企业的重要资产,能够帮助企业洞察市场动态、优化业务流程、提升客户满意度、创造竞争优势。然而,传统的BI(商业智能࿰…...
nginx文件配置
在部署前后端分离项目时,当前端和后端不在一个服务器上时,需要在前端服务器上下载nginx并配置 #hkdp-front-test 前端服务器 xxx.xxx.x.69 前端项目端口号9528,监听文件夹 /home/apps/vue/hkdp-manager 配置如下 server{ …...
视频云存储/安防监控EasyCVR视频汇聚平台如何通过角色权限自行分配功能模块?
视频云存储/安防监控EasyCVR视频汇聚平台基于云边端智能协同,支持海量视频的轻量化接入与汇聚、转码与处理、全网智能分发、视频集中存储等。音视频流媒体视频平台EasyCVR拓展性强,视频能力丰富,具体可实现视频监控直播、视频轮播、视频录像、…...
小程序定位到 胶囊的三个点大概中间
话不多说,先上效果图 这个功能实现思路: 首先先拿到这一张整图(快捷,精确)然后获取整个导航栏高度(自定义导航栏,非自定义导航栏忽略这一步)获取三个点的做偏移量,把高度和偏移量给到一个定位到盒子,这个盒子里就放这个图片&…...
Maven详解
文章目录 一、引言1.1 为什么需要 Maven?1.2 Maven 解决了哪些问题?1.2.1 添加第三方jar包1.2.2 jar包之间的依赖关系1.2.3 处理jar包之间的冲突1.2.4 获取第三方jar包1.2.5 将项目拆分成多个工程模块1.2.6 实现项目的分布式部署 二、介绍三、Maven 的特…...
音视频 ffplay命令-高级选项
选项说明-stats打印多个回放统计信息,包括显示流持续时间,编解码器参数,流中的当前位置,以及音频/视频同步差值。默认情况下处于启用状态,要显式禁用它则需要指定-nostats-fast非标准化规范的多媒体兼容优化-genpts生成…...
[管理与领导-44]:IT基层管理者 - 个人管理 - 从掌握管理知识开始入门:管理的常识和基础
目录 前言:管理框架 一、什么是管理 1.1 以终为始 1.2、资源的优化配置(人财物、权力、时间等资源) 1.2.1 资源的优化配置的步骤 1.2.2 管理者拥有的资源 1.2.3 管理者的权力资源 1.3 分而治之 1.3.1 分目标:细化和分解目…...
c#两个数进行交换
1.使用中间变量的形式 private static void Main(string[] args){int a110;int a220;ChangeNumber(ref a1,ref a2)onsole.WriteLine($"a1的值{a1},a2的值{a2}");Console.ReadLine();}public static void ChangeNumber(ref int a1, ref int a2){int temp a1;//temp10…...
51c自动驾驶~合集58
我自己的原文哦~ https://blog.51cto.com/whaosoft/13967107 #CCA-Attention 全局池化局部保留,CCA-Attention为LLM长文本建模带来突破性进展 琶洲实验室、华南理工大学联合推出关键上下文感知注意力机制(CCA-Attention),…...
定时器任务——若依源码分析
分析util包下面的工具类schedule utils: ScheduleUtils 是若依中用于与 Quartz 框架交互的工具类,封装了定时任务的 创建、更新、暂停、删除等核心逻辑。 createScheduleJob createScheduleJob 用于将任务注册到 Quartz,先构建任务的 JobD…...
python如何将word的doc另存为docx
将 DOCX 文件另存为 DOCX 格式(Python 实现) 在 Python 中,你可以使用 python-docx 库来操作 Word 文档。不过需要注意的是,.doc 是旧的 Word 格式,而 .docx 是新的基于 XML 的格式。python-docx 只能处理 .docx 格式…...
大模型多显卡多服务器并行计算方法与实践指南
一、分布式训练概述 大规模语言模型的训练通常需要分布式计算技术,以解决单机资源不足的问题。分布式训练主要分为两种模式: 数据并行:将数据分片到不同设备,每个设备拥有完整的模型副本 模型并行:将模型分割到不同设备,每个设备处理部分模型计算 现代大模型训练通常结合…...
Java面试专项一-准备篇
一、企业简历筛选规则 一般企业的简历筛选流程:首先由HR先筛选一部分简历后,在将简历给到对应的项目负责人后再进行下一步的操作。 HR如何筛选简历 例如:Boss直聘(招聘方平台) 直接按照条件进行筛选 例如:…...
安宝特方案丨船舶智造的“AR+AI+作业标准化管理解决方案”(装配)
船舶制造装配管理现状:装配工作依赖人工经验,装配工人凭借长期实践积累的操作技巧完成零部件组装。企业通常制定了装配作业指导书,但在实际执行中,工人对指导书的理解和遵循程度参差不齐。 船舶装配过程中的挑战与需求 挑战 (1…...
Mysql中select查询语句的执行过程
目录 1、介绍 1.1、组件介绍 1.2、Sql执行顺序 2、执行流程 2.1. 连接与认证 2.2. 查询缓存 2.3. 语法解析(Parser) 2.4、执行sql 1. 预处理(Preprocessor) 2. 查询优化器(Optimizer) 3. 执行器…...
三分算法与DeepSeek辅助证明是单峰函数
前置 单峰函数有唯一的最大值,最大值左侧的数值严格单调递增,最大值右侧的数值严格单调递减。 单谷函数有唯一的最小值,最小值左侧的数值严格单调递减,最小值右侧的数值严格单调递增。 三分的本质 三分和二分一样都是通过不断缩…...
Vue 模板语句的数据来源
🧩 Vue 模板语句的数据来源:全方位解析 Vue 模板(<template> 部分)中的表达式、指令绑定(如 v-bind, v-on)和插值({{ }})都在一个特定的作用域内求值。这个作用域由当前 组件…...
快速排序算法改进:随机快排-荷兰国旗划分详解
随机快速排序-荷兰国旗划分算法详解 一、基础知识回顾1.1 快速排序简介1.2 荷兰国旗问题 二、随机快排 - 荷兰国旗划分原理2.1 随机化枢轴选择2.2 荷兰国旗划分过程2.3 结合随机快排与荷兰国旗划分 三、代码实现3.1 Python实现3.2 Java实现3.3 C实现 四、性能分析4.1 时间复杂度…...
