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

【Spring】深入解析 Spring AOP 核心概念:切点、连接点、通知、切面、通知类型和使用 @PointCut 定义切点的方法

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述


Spring AOP


下面我们再来详细学习 AOP,主要是以下几部分:

image-20250421182852776


Spring AOP 核心概念


image-20250421114620399


切点(Pointcut)


切点(Pointcut),也称之为“切入点”。

Pointcut 的作用就是提供一组规则(使用 AspectJ pointcut expression language 来描述),告诉程序对哪些方法来进行功能增强。

image-20250421112458255

上面的表达式 execution(* com.example.demo.controller.*.*(..)) 就是切点表达式。


连接点(Join Point)


满足切点表达式规则方法,就是连接点。也就是可以被 AOP 控制的方法。

以入门程序举例,所有 com.example.demo.controller 路径下的方法,都是连接点。

image-20250421114123462

上述 BookController 中的方法都是连接点。


image-20250421152705933


切点和连接点的关系:

  • 连接点是满足切点表达式元素切点可以看做是保存了众多连接点的一个集合。 比如:
  • 切点表达式:全体偶像练习生
  • 连接点就是:蔡徐坤、范丞丞等各个偶像练习生

通知(Advice)


通知就是具体要做的工作,指哪些重复的逻辑,也就是共性功能最终体现为一个方法)。

比如上述程序中记录业务方法的耗时时间,就是通知

image-20250421114310008

在 AOP 面向切面编程当中,我们把这部分重复的代码逻辑抽取出来单独定义,这部分代码就是通知的内容。


切面(Aspect)


切面(Aspect)= 切点(Pointcut)+ 通知(Advice)。

通过切面就能够描述当前 AOP 程序需要针对于哪些方法,在什么时候执行什么样的操作。

切面既包含了通知逻辑的定义,也包括了连接点的定义。

image-20250421114337427

切面所在的类,我们一般称为切面类(被 @Aspect 注解标识的类)。


通知类型


上面我们讲了什么是通知,接下来学习通知的类型@Around 就是其中一种通知类型,表示环绕通知

image-20250421114423462


Spring 中 AOP通知类型有以下几种:

注解名称描述
@Around环绕通知,此注解标注的通知方法在目标方法前、后都被执行。
@Before前置通知,此注解标注的通知方法在目标方法前被执行。
@After后置通知,此注解标注的通知方法在目标方法后被执行的,无论是否有异常都会执行。
@AfterReturning返回后通知,此注解标注的通知方法在目标方法后被执行的,有异常不会执行。
@AfterThrowing异常后通知,此注解标注的通知方法在发生异常后执行。

接下来我们通过代码来加深对这几个通知的理解:

为方便学习,我们可以新建一个项目,使用 web+lombok 依赖,删除 pom.xml 文件多余部分:

image-20250421130421846


添加 AOP 依赖:

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId>
</dependency>

先创建测试类接口:

image-20250421130303873


添加连接点:

image-20250421131054719


创建切面(需引入 AOP 依赖):

image-20250421132632270

@Slf4j
@Aspect
@Component
public class AspectDemo1 {/*** @Around(环绕通知):此注解标注的通知方法在目标执行前,后都被执行*/@Around("execution(* com.bit.springaopdemo.Controller.*.*(..))")public Object TimeAspect(ProceedingJoinPoint pjp) throws Throwable {log.info("目标方法执行前.......");Object result = pjp.proceed();log.info("目标方法执行后.......");return result;}/*** @Before(前置通知),此注解标注的通知方法在目标方法前被执行*/@Before("execution(* com.bit.springaopdemo.Controller.*.*(..))")public void doBefore(){log.info("doBefore.......");}/*** @After(后置通知),此注解标注的通知方法在目标方法后被执行的,无论是否有异常都会执行。*/@After("execution(* com.bit.springaopdemo.Controller.*.*(..))")public void doAfter(){log.info("doAfter.......");}/*** @AfterReturning(返回后通知),此注解标注的通知方法在目标方法后被执行的,有异常不会执行。*/@AfterReturning("execution(* com.bit.springaopdemo.Controller.*.*(..))")public void doAfterReturning(){log.info("AfterReturning.......");}/*** @AfterThrowing(异常后通知),此注解标注的通知方法在发生异常后执行。*/@AfterThrowing("execution(* com.bit.springaopdemo.Controller.*.*(..))")public void doAfterThrowing(){log.info("AfterThrowing.......");}
}

运行程序,观察日志:


1、正常运行的情况:


http://127.0.0.1:8080/test/t1

image-20250421150515643


观察日志:

image-20250421150603225


这个日志中,我们还是不知道目标方法 t1() 是什么时候执行的,再打上一个日志,重新运行程序,并发送请求:

image-20250421150959335


程序正常运行的情况下,@AfterThrowing 标识的通知方法不会执行。

image-20250421153218053

从上图也可以看出来,@Around 标识的通知方法包含两部分,一个“前置逻辑”,一个“后置逻辑”


其中“前置逻辑”会先于 @Before 标识的通知方法执行,“后置逻辑”会晚于 @After 标识的通知方法执行:

image-20250420172341060


2、异常时的情况:


为了方便观察,我们给 Controller 中的每个接口都加上 log 日志:

image-20250421151534707


测试方法 t1() 是没有异常的情况,接下来,我们来测试目标方法存在异常的情况:

image-20250421151755261


观察日志:

image-20250421151927017


程序发生异常的情况下:

  • @AfterReturning 标识的通知方法不会执行;

  • @AfterThrowing 标识的通知方法执行了;

image-20250421152232823


如果我们在环绕通知 @Around 中,使用 try....catch .....连接点(目标方法)的异常进行捕获,能否达到 @AfterThrowing 的功能呢?

image-20250421160235500


@Around 环绕通知中原始方法调用时有异常,通知中的环绕后的代码逻辑也不会再执行了(因为原始方法调用出异常了)。

image-20250421154553448


image-20250420172434125


注意事项:

  • @Around 环绕通知需要调用 ProceedingJoinPoint.proceed() 来让原始方法执行其他通知不需要考虑目标方法执行

  • @Around 环绕通知 的方法返回值,必须指定为 Object,来接收原始方法的返回值,否则原始方法执行完毕,是获取不到返回值的。

  • 一个切面类可以有多个切点


定义切点@PointCut


上面代码存在一个问题,就是存在大量重复的切点表达式:

execution(* com.example.demo.controller.*.*(..))


Spring 提供了 @PointCut 注解,把公共的切点表达式提取出来,需要用到时引用该切入点表达式即可。

上述代码就可以修改为:

image-20250421163815187


image-20250421164457806


当切点定义使用 private 修饰时,仅能在当前切面类中使用。

image-20250421164719422


其他切面类也要使用当前切点定义时,就需要把 private 改为 public

image-20250421165159178


引用方式为:全限定类名.方法名()

image-20250421165100748


在这里插入图片描述

在这里插入图片描述

相关文章:

  • 安装Github软件详细流程,win10系统从配置git到安装软件详解,以及github软件整合包制作方法(
  • BUUCTF PWN刷题笔记(1-9)
  • LangChain与图数据库Neo4j LLMGraphTransformer融合:医疗辅助诊断、金融风控领域垂直领域、法律咨询场景问答系统的技术实践
  • 垂直行业突围:工业软件在汽车、航空领域的 “破壁” 实践
  • Google Store 如何利用 glTF 3D 模型改变产品教育
  • 每日一题——数据中心网络地址规划
  • 解决离线部署气隙相关问题
  • 35、Python 异步编程入门与asyncio从原理到实战
  • Itext进行PDF的编辑开发
  • .NET应用UI框架DevExpress XAF v24.2新版亮点:支持.NET 9
  • 如何远程访问家中服务器-FRP内网穿透详细
  • 2025年蓝桥杯第十六届CC++大学B组真题及代码
  • 《Java工程师面试核心突破》专栏简介
  • 多源异构网络安全数据(CAPEC、CPE、CVE、CVSS、CWE、ATTCK、D3FEND)的详细解析,包括其作用、数据内容及相互联系
  • Dynamics 365 Business Central Job Queue 详解
  • n2n 搭建虚拟局域网,实现内网穿透
  • Node.js和js到底什么关系
  • 制作一款打飞机游戏16:空间优化
  • 高并发内存池项目
  • 第十四届蓝桥杯 2023 C/C++组 有奖问答
  • 话剧《门第》将开启全国巡演:聚焦牺牲、爱与付出
  • 商务部:试点示范已形成9批190多项创新成果向全国推广
  • 用8年还原曹操墓鉴定过程,探寻曹操墓新书创作分享会举行
  • 深化应用型人才培养,这所高校聘任行业企业专家深度参与专业设置
  • 从6家试点扩展至全行业,券商并表监管有何看点?
  • 张宝亮任山东临沂市委书记