【Spring】AOP中的核心概念:通知(Advice)和切点(Pointcut)

目录

1、通知(Advice)

1.1、前置通知

1.2、后置通知

1.3、返回通知

1.4、异常通知

1.5、通知的执行顺序

2、切点(Pointcut)

2.1、切点表达式的抽取

2.2、切点标识符

2.2.1、execution

2.2.2、within

2.2.3、@annotation

1、通知(Advice)

通知(Advice):在切面的某个特定的连接点上执行的动作。通知有多种类型,包括“around”,“before” 和“after”等等。通知的类型将在后面详细了解。许多AOP框架,包括Spring在内,都是以拦截器做通知模型的,并维护着一个以连接点为中心的拦截器链。

用来放增强的代码的那个方法

  • 环绕通知@Around:可以把代码增强在目标方法的任意地方,更通用
  • 前置通知@Before:目标方法之前执行
  • 后置通知@After:目标方法之后执行
  • 异常通知@AfterThrowing:目标方法出现了异常执行
  • 返回通知@AfterReturning:目标方法返回值执行

这是一个自定义类UserService,假设其所有业务功能都已经实现,在后面的示例中可能会修改一些代码

//自定义类UserService
@Service
public class UserService {// 增加增删改查方法,这里就用一个打印语句来代替具体的方法功能了public void add(){System.out.println("增加");}public void delete(){System.out.println("删除");}public void update(){System.out.println("修改");}public void query(){System.out.println("查询");}
}

这是一个切面类,用于辅助理解各种通知类型

@Aspect  //把这个类标记为切面类
@Component  //切面类必须声明为Spring的bean
public class LogAspect {//后续在这会写各种通知的代码}

这是一个测试类,在里面获取UserService的bean,然后调用他里面的方法进行测试

@SpringBootTest(classes = AdviceTest.class)
@ComponentScan
@EnableAspectJAutoProxy
public class AdviceTest {@Testvoid contextLoads(@Autowired UserService userService) {userService.query(); //这里调用的方法不是固定的}}

1.1、前置通知

前置通知@Before:目标方法之前执行,即在连接点之前进行执行

示例:

//自定义类UserService,假设其所有业务功能都已经实现
@Service
public class UserService {//......这里的代码不变public void delete(long id){System.out.println("删除");}//......这里的代码不变
}//切面类LogAspect
@Aspect  //把这个类标记为切面类
@Component  //切面类必须声明为Spring的bean
public class LogAspect {//前置通知@Before("execution(* com.lt.advice.UserService.*(..))")public void before(JoinPoint joinPoint){//记录当前方法的方法名,参数String methodName = joinPoint.getSignature().getName();//参数Object[] args = joinPoint.getArgs();//目标对象Object target = joinPoint.getTarget();System.out.println("当前执行的方法是" + target.getClass() + "." + methodName + ": 参数" + Arrays.toString(args));}
}//测试类AdviceTest
@SpringBootTest(classes = AdviceTest.class)
@ComponentScan
@EnableAspectJAutoProxy
public class AdviceTest {@Testvoid contextLoads(@Autowired UserService userService) {userService.delete(1L);//调用delete方法进行测试}
}

运行结果:

1.2、后置通知

后置通知@After:目标方法之后执行,就是在连接点方法完成之后执行,无论连接点方法执行成功还是出现异常,都将执行后置方法。

示例:

//切面类LogAspect
@Aspect  //把这个类标记为切面类
@Component  //切面类必须声明为Spring的bean
public class LogAspect {//前置通知@Before("execution(* com.lt.advice.UserService.*(..))")public void before(JoinPoint joinPoint){//......这里的代码不变}//后置通知@After("execution(* com.lt.advice.UserService.*(..))")public void after(JoinPoint joinPoint){// 在这里也可以获得目标方法的一些信息,这里就不再演示了,简单的执行一条打印语句就好了System.out.println("后置通知");}}

运行结果:

1.3、返回通知

返回通知@AfterReturning:目标方法返回值执行。当目标方法(连接点方法)成功执行后,返回通知方法才会执行,如果目标方法出现异常,则返回通知方法不执行。返回通知方法在目标方法执行成功后才会执行,所以,返回通知方法可以拿到目标方法执行后的结果。

切面类中定义返回通知方法,示例如下:

//自定义类UserService,假设其所有业务功能都已经实现
@Service
public class UserService {// 增加增删改查方法,这里就用一个打印语句来代替具体的方法功能了//......这里的代码不变public Object query(){System.out.println("查询");return null;}
}切面类LogAspect
@Aspect  //把这个类标记为切面类
@Component  //切面类必须声明为Spring的bean
public class LogAspect {//前置通知和后置通知//......这里的代码不变// 返回通知:可以获取返回值,在后置通知之前执行@AfterReturning(value = "execution(* com.lt.advice.UserService.*(..))", returning = "returnValue")public void afterReturning(JoinPoint joinPoint, Object returnValue){System.out.println("返回通知:" + returnValue);//输出返回的结果}}@SpringBootTest(classes = AdviceTest.class)
@ComponentScan
@EnableAspectJAutoProxy
public class AdviceTest {@Testvoid contextLoads(@Autowired UserService userService) {userService.query();//调用query方法进行测试}}

1.4、异常通知

异常通知@AfterThrowing:目标方法出现了异常执行。异常通知方法只在连接点方法出现异常后才会执行,否则不执行。在异常通知方法中可以获取连接点方法出现的异常。

在切面类中异常通知方法,示例如下:

//自定义类UserService,假设其所有业务功能都已经实现
@Service
public class UserService {// 增加增删改查方法,这里就用一个打印语句来代替具体的方法功能了//......这里的代码不变public void update(){System.out.println("修改");throw new RuntimeException("出错了~~"); //自定义一个异常,用于测试异常通知}//......这里的代码不变
}//切面类LogAspect
@Aspect  //把这个类标记为切面类
@Component  //切面类必须声明为Spring的bean
public class LogAspect {//前置通知、后置通知和返回通知//......这里的代码不变//异常通知@AfterThrowing(value = "execution(* com.lt.advice.UserService.*(..))", throwing = "exception")public void afterThrowing(JoinPoint joinPoint, Exception exception){System.out.println("异常通知:" + exception.getMessage()); //输出异常信息}}//测试类AdviceTest
@SpringBootTest(classes = AdviceTest.class)
@ComponentScan
@EnableAspectJAutoProxy
public class AdviceTest {@Testvoid contextLoads(@Autowired UserService userService) {userService.update();//调用update方法进行测试}}

1.5、通知的执行顺序

正常情况:前置--->目标方法--->返回通知--->后置通知(finally)

异常情况:前置--->目标方法--->异常通知--->后置通知(finally)

2、切点(Pointcut)

切点(Pointcut):匹配连接点的断言。通知和切点表达式相关联,并在满足这个切点的连接点上运行(例如,当执行某个特定名称的方法时)。切点表达式如何和连接点匹配是AOP的核心:Spring默认使用Aspectj切点语义。

增强代码要对哪些类中的哪些方法进行增强,进行切割,指的是被增强的方法,即要切哪些东西。切点表达式

2.1、切点表达式的抽取

        通过抽取切点表达式,可以将关注点分离,提高代码的模块化和可维护性。同时,抽取后的切点表达式具有更高的重用性,可以在不同的切面中共享使用。并且,代码的可读性和可维护性也会得到提升,开发者能更清晰地理解和管理切点,方便后续的修改和调整。最重要的是,抽取切点表达式有助于降低代码之间的耦合度,使系统更加灵活和可扩展。

        抽取切点表达式的实现:先声明一个方法,这个方法里面不需要写任何代码,然后在这个方法上利用@Pointcut注解去声明一个切点表达式,之后就可以在各种通知当中去引用这个加了@Pointcut注解的切点方法名了,这就相当于把@Pointcut注解声明的切点表达式给引用过来了

示例:

//切面类LogAspect
@Aspect  //把这个类标记为切面类
@Component  //切面类必须声明为Spring的bean
public class LogAspect {//声明一个方法,来抽取切点表达式@Pointcut("execution(* com.lt.pointcut.UserService.*(..))")public void pointcut(){}//前置通知@Before("pointcut()") //引用抽取了的切点表达式public void before(JoinPoint joinPoint){//记录当前方法的方法名,参数String methodName = joinPoint.getSignature().getName();//获取参数Object[] args = joinPoint.getArgs();//获取目标对象Object target = joinPoint.getTarget();System.out.println("当前执行的方法是" + target.getClass() + "." + methodName + ": 参数" + Arrays.toString(args));}//后置通知@After("pointcut()") //引用抽取了的切点表达式public void after(JoinPoint joinPoint){System.out.println("后置通知");}// 返回通知:可以获取返回值,在后置通知之前执行@AfterReturning(value = "pointcut()", returning = "returnValue")public void afterReturning(JoinPoint joinPoint, Object returnValue){System.out.println("返回通知:" + returnValue);//returnValue是返回值}//异常通知@AfterThrowing(value = "pointcut()", throwing = "exception")public void afterThrowing(JoinPoint joinPoint, Exception exception){System.out.println("异常通知:" + exception.getMessage()); //输出异常信息}}

2.2、切点标识符

2.2.1、execution

execution是切点标识符,用于匹配方法执行连接点。,execution是使用Spring AOP时使用的主要切点标识符,可以匹配到方法级别(就是可以去匹配规定的要具体到哪一个方法),细粒度

(1)访问修饰符:不写代表所有

(2)返回值:*代表所有

(3)完整限定名:

        包名:*代表任何包名,而 ..代表子孙包

                com.lt.service = service包

                com.lt.* = com.lt.service、 com.lt.dao、 com.lt.xxx 等。包名任意不代表层级任意

                com.lt.. = com.lt.service.imple、 com.lt.service.depend 等。代表层级任意

        类:*代表所有类

                com.lt..* = com.lt.service.imple.任意包. 任意类

        参数:不写代表没有参数的方法 而 ..代表任意参数

2.2.2、within

within只能匹配类这一级别,只能指定类, 类下面的某个具体的方法无法指定, 粗粒度

示例:如果想让execution和within的切点表达式都生效,可以在引用时使用 && 实现

@Aspect  //把这个类标记为切面类
@Component  //切面类必须声明为Spring的bean
public class LogAspect {//execution 方法级别@Pointcut("execution(* com.lt.pointcut.UserService.*(..))")public void pointcut(){}//within 类级别=UserService所有的方法@Pointcut("within()* com.lt.pointcut.UserService)")public void pointcutWithIn(){}//前置通知@Before("pointcut() && pointcutWithIn()")//使用 && 让execution和within的切点表达式都生效public void before(JoinPoint joinPoint){//记录当前方法的方法名,参数String methodName = joinPoint.getSignature().getName();//参数Object[] args = joinPoint.getArgs();//目标对象Object target = joinPoint.getTarget();System.out.println("当前执行的方法是" + target.getClass() + "." + methodName + ": 参数" + Arrays.toString(args));}}

2.2.3、@annotation

@annotation:限制匹配连接点(在Spring AOP中执行的方法具有给定的注解)

假设我需要记录每个方法详细作用,并且记录数据库日志表。这时候就可以用@annotation注解来作为切点标识符,因为@annotation匹配到的是方法上的注解

示例:

先自定义一个注解Log

@Retention(RetentionPolicy.RUNTIME)  //注解的保留
@Target({ElementType.METHOD})  //可以标记的地方
public @interface Log {String value();//用于记录方法的作用
}

这是一个自定义类UserService

@Service
public class UserService {//加上自定义的注解,并写上add()方法的作用@Log("用户增加方法")public void add(){System.out.println("增加");}}

这是一个切面类LogAspect

@Aspect  //把这个类标记为切面类
@Component  //切面类必须声明为Spring的bean
public class LogAspect {//execution 方法级别@Pointcut("execution(* com.lt.pointcut.UserService.*(..))")public void pointcut(){}//within 类级别=UserService所有的方法@Pointcut("within(com.lt.pointcut.UserService)")public void pointcutWithIn(){}//Pointcut 所有的方法有log注解都会匹配//如果要在通知的参数中绑定注解就不能单独抽取//如果要在通知的参数中绑定注解,声明就是参数名了,不是注解类型!@Pointcut("@annotation(Log)")public void pointcutAnnotation(){}//前置通知//@Before("pointcut() && pointcutWithIn() && @annotation(log)")@Before("@annotation(log)")//@Before中的参数需要填@annotation(log),而不是pointcutAnnotation()public void before(JoinPoint joinPoint, Log log){//记录当前方法的方法名,参数String methodName = joinPoint.getSignature().getName();//参数Object[] args = joinPoint.getArgs();//目标对象Object target = joinPoint.getTarget();System.out.println("当前执行的方法是" + target.getClass() + "." + methodName + ": 参数" + Arrays.toString(args));//获取注解信息System.out.println("当前方法的作用是:" + log.value());}}

测试类AdviceTest 

@SpringBootTest(classes = AdviceTest.class)
@ComponentScan
@EnableAspectJAutoProxy
public class AdviceTest {@Testvoid contextLoads(@Autowired UserService userService) {userService.add();}}
运行结果:

推荐:

【Spring】初识 Spring AOP(面向切面编程)-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/m0_65277261/article/details/138724937?spm=1001.2014.3001.5501【Spring】Bean的生命周期回调函数和Bean的循环依赖-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/m0_65277261/article/details/138503989?spm=1001.2014.3001.5501【Spring】IOC/DI中常用的注解@Lazy、@Scope与@Conditional-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/m0_65277261/article/details/138277932?spm=1001.2014.3001.5501

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/1425261.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

mybaties查询!!!你就说灵不灵活吧

你就说灵不灵活吧 <?xml version"1.0" encoding"UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace"com.ruoyi.sys…

白鲸开源CEO郭炜在2024 DataOps发展大会上获聘专家

2024年5月15日&#xff0c;白鲸开源CEO郭炜在2024 DataOps发展大会上被正式聘任为DataOps专家&#xff0c;并获得了荣誉证书。本次大会由中国通信标准化协会主办&#xff0c;中关村科学城管委会提供支持&#xff0c;大数据技术标准推进委员会&#xff08;CCSATC601&#xff09;…

CSS之浮动

目录 浮动常见网页布局标准流&#xff08;普通流、文档流&#xff09;为什么需要浮动什么是浮动浮动特性&#xff08;重难&#xff09;注意&#xff1a;清除浮动 浮动 常见网页布局 本质&#xff1a;用CSS来摆放盒子&#xff0c;把盒子摆放到相应的位置 三种常见布局方式&…

【亚马逊云】注册APN账号及报考AWS认证考试说明演示

文章目录 1. 登录AWS网站2. 注册APN账号3. 更改APN账号密码&#xff08;选&#xff09;4. 修改APN账号信息&#xff08;选&#xff09;5. 查看AWS认证情况&#xff08;选&#xff09;6. AWS认证考试报名流程7. 修改报名控制台语言版本&#xff08;选&#xff09;8. 开始报名AWS…

首战告捷!KCM Trade漂移队出征2024日本漂移锦标赛(FDJ2)

卓越之姿&#xff0c;非凡之势&#xff01;KCM Trade漂移队以实力点燃激情 当激情与速度交织&#xff0c;当硝烟四起的战场转移到赛车领域&#xff0c;我们见证了一场精彩绝伦、实力与策略并存的较量——KCM Trade漂移队在2024日本漂移锦标赛&#xff08;FDJ2&#xff09;上展现…

专项培训:实在智能携手中国总会计师协会,共襄金融行业数字化转型

6月19日—23日&#xff0c;中国总会计师协会即将在浙江杭州举办“基于大模型的 AI Agent数字员工在金融行业实践应用专项培训”。本次培训旨在深入探讨和实践人工智能技术在金融行业的应用&#xff0c;推动金融行业的智能化和高效化发展。 作为本次培训的协办单位&#xff0c;…

软考--软件设计师--试题六--工厂方法模式(Factory Method)

工厂方法模式(Factory Method) 1、意图 定义一个用于创建对象的接口&#xff0c;让子类决定实例化哪儿一个类&#xff0c;factory method使一个类的实例化延迟到其子类。 2、结构 3、适用性 a、当一个类不知道它所必须创建的对象的类的时候。 b、当一个类希望由它的子类来指定…

第二证券股市技巧|港股交易规则有哪些?

港股商场作为全球首要的股票商场之一&#xff0c;招引了很多出资者的目光。关于港股的生意规则有哪些&#xff0c;第二证券下面就为大家详细介绍一下。 港股的生意规则&#xff1a; 1、港股生意时刻&#xff1a;港股商场的生意时刻分为上午和下午两个时段&#xff0c;上午的生…

零知识证明:哈希函数-Poseidon2代码解析与benchmark

1、哈希函数(Hash Function)与Poseidon 在密码学中,哈希函数是一种将任意大小的数据映射到固定大小的输出的函数。哈希函数的输出称为哈希值或哈希码。哈希函数具有单向性和抗碰撞性。一些常见的哈希函数包括 MD5、SHA-1、SHA-256 和 SHA-3。例如,假设您要验证一个文件的完整…

第八篇 Asciidoc 输出 All In One HTML 解决图片无法显示问题

问题:我的图片显示不出来了 小明使用 Asciidoc 来记笔记,他将笔记输出为 HTML 文件。小丽向小明借笔记。小明将 Asciidoc 笔记输出为 HTML文件,并拷贝给了小丽。 但是,小丽发现,图片都显示不出来了。 小丽:小明,你给我的笔记,图片都显示不出来啊。 小明:是我给你的…

2024CCPC郑州邀请赛暨河南省赛(A,B,C,D,F,G,H,J,K,L,M)

2024 National Invitational of CCPC (Zhengzhou), 2024 CCPC Henan Provincial Collegiate Programming Contest 2024 年中国大学生程序设计竞赛全国邀请赛&#xff08;郑州&#xff09;暨第六届 CCPC 河南省大学生程序设计竞赛 比赛链接 这场的题说实话难度其实都不大&…

AndroidStudio集成高德地图后出现黑屏并报错

报错内容为&#xff1a;No implementation found for void com.autonavi.base.ae.gmap.GLMapEngine.nativeMainThreadTrigger(int, long) (tried Java_com_autonavi_base_ae_gmap_GLMapEngine_nativeMainThreadTrigger and Java_com_autonavi_base_ae_gmap_GLMapEngine_nativeM…

金蝶AAS-V9.0前后端部署

前言 包含金蝶AAS9.0部署&#xff0c;前端部署&#xff0c;后端部署。 金蝶AAS9.0部署 1. 下载金蝶AAS9.0安装包上传至服务器&#xff1b; 2. 解压安装包&#xff1b; unzip -d /opt/AAS-V9.0 AAS-V9.0.zip3. 配置JAVA路径&#xff1b; echo $JAVA_HOME vim /opt/AAS-9.0…

06_机器学习算法_朴素贝叶斯

1. 朴素贝叶斯的介绍与应用 1.1 朴素贝叶斯的介绍 朴素贝叶斯算法(Naive Bayes, NB)是应用最为广泛的分类算法之一。它是基于贝叶斯定义和特征条件独立假设的分类方法。由于朴素贝叶斯法基于贝叶斯公式计算得到,有着坚实的数学基础,以及稳定的分类效率。NB模型所需估计的…

Mac SourceTree配置ssh git仓库

一、准备条件 1、Mac系统电脑 2、安装好SourceTree 3、获取ssh git仓库地址 二、配置步骤 1、打开终端命令行 ssh -t rsa -C "xxx""xxx"代表注册git仓库时&#xff0c;使用的用户名&#xff0c;可以是字符串也可以是邮箱地址。 如果遇到输入密码&#xf…

2024MySQL8安装与绿色版Navicat连接【提供安装包】数据库

视频教程面向人群和使用方法&#xff1a; 1&#xff1a;大学生【解决老师作业或自己兴趣学习需要】; 2&#xff1a;第一次需要安装MySQL的开发者【需要简单使用&#xff0c;因为项目会用到】 3&#xff1a;老手二倍速&#xff0c;新手老老实实按照教程一倍速模仿视频操作&am…

照明灯具十大排名哪个品牌好?照明灯具前十名排行榜大公开!

照明灯具十大排名哪个品牌好&#xff1f;护眼台灯作为照明灯具的重要组成部分&#xff0c;其品质与品牌选择显得尤为关键&#xff0c;市面上品质比较好的护眼台灯品牌有书客、明基、松下等品牌。本文旨在为大家揭晓照明灯具十大排名中的佼佼者&#xff0c;揭示照明灯具前十名的…

思科期末大作业

计算机网络&#xff0c;可代写网络作业&#xff0c; 思科cisco模拟器&#xff0c;eve&#xff0c;制作校园局域网、企业局域网&#xff0c;实现路由交换、单臂路由、冗余、ACL、Nat、PAT、DHCP,RIP,OSPF,pppoe等技术&#xff0c;价格合理&#xff0c;详细私聊

原创|手把手教你构建评分卡模型

作者&#xff1a;胡赟豪‍‍‍‍ 本文约2800字&#xff0c;建议阅读5分钟 本文介绍了构建评分卡模型。‍‍‍ 一、背景 在各种机器学习、深度学习模型快速发展的当下&#xff0c;评分卡模型作为一种可解释机器学习模型&#xff0c;仍然在金融、营销等领域被广泛使用。这一模型通…

vue嵌套路由

一、嵌套 children配置 1.父类路由 mymusic 2.子类路由 musicson 1.创建MusicSon组件 <template><div><p>从前和后来</p><p>唯一</p><p>运气来的似有若无</p></div> </template><script>export defaul…