Skip to main content

aspect

AOP 中模块化的关键单元是切面。切面能够对跨越多种类型和对象的关注点(例如事务管理)进行模块化

concept

1. 切面 (Aspect):你要实现的“功能模块”

  • 官方定义:横切关注点的模块化(如事务、日志)。
  • 大白话:切面就是一个普通的类,里面放着那些**“到处都要用,但跟核心业务逻辑无关”**的代码。比如,“记录日志”就是一个切面。

2. 连接点 (Join point) 与 切入点 (Pointcut)

  • 连接点 (Join point)“哪里可以切”。在 Spring AOP 里,每一个方法的执行点都是连接点。
  • 切入点(Pointcut):匹配连接点的谓词。通知(advice)与切入点表达式关联,并在切入点匹配的任何连接点处运行(例如,执行具有特定名称的方法)
  • 类比:医生在人体上可以动手术的地方(皮肤、器官)都是连接点,但医生今天只想给“阑尾”动手术,那么“阑尾所在的那个点”就是切入点。
  • pcd 详解切入点表达式

3. 通知 (Advice):“切了之后做什么”

切面在特定连接点处采取的操作。通知的类型包括“周围通知”、“之前通知”和“之后通知”

  • Before advice: 在连接点之前运行的通知,但无法阻止执行流程继续到连接点(除非抛出异常)
  • After returning advice: 在连接点正常完成后要运行的通知(例如,如果方法返回时没有抛出异常)
  • After throwing advice: 如果方法因抛出异常而退出,则要运行此建议
  • After (finally) advice: 无论连接点以何种方式退出(正常或异常返回),都要运行该建议
  • Around advice: 围绕连接点(例如方法调用)的通知。这是功能最强大的通知类型。 环绕式通知可以在方法调用前后执行自定义行为。它还负责决定是继续执行连接点,还是通过返回自身返回值或抛出异常来跳过被建议的方法执行

4. 目标对象 (Target) 与 AOP 代理 (AOP Proxy)

  • 目标对象:就是你写的原始业务类(比如 UserService)。
  • AOP 代理:Spring 为了实现 AOP,不会让你直接调用原始类,而是给你一个**“替身”**(代理类)。你调用代理类时,它会先执行你的“切面逻辑”,再去调用真正的业务逻辑。

织入 (Weaving)

织入是将切面代码插入到目标对象的过程。

  • Spring AOP 采用的是 运行时织入
  • 这意味着你的代码在编译成 .class 文件时还是干净的,只有当程序跑起来,Spring 容器初始化 Bean 的时候,才会动态地为你生成一个代理对象,把切面代码“织”进去。

Introduction

直接给类增加新的功能或身份(改变结构)

Introduction: :为类型声明额外的方法或字段。Spring AOP 允许您向任何对象引入新的接口(以及相应的实现)。建议对象。 例如,可以使用引入来使 bean 实现一个 IsModified 接口,用于简化缓存。(在 AspectJ 社区中,这种引入被称为类型间声明。)

进阶指导:建议使用最简单的通知类型。

  • 环绕通知 (Around) 的强大之处在于它拥有 ProceedingJoinPoint 对象。如果你忘记调用 proceed() 方法,原本的业务逻辑就永远不会执行
  • 对比建议:如果你只是想在方法执行完记录个日志,用 AfterReturning 就够了。这样代码意图更清晰,也避免了因忘记调用 proceed() 导致的严重 Bug。

总结:AOP 的工作流程图

  1. 定义切面 (Aspect):写一个类,放横切逻辑。
  2. 定义切入点 (Pointcut):写表达式,告诉 Spring 拦截哪些类、哪些方法。
  3. 编写通知 (Advice):决定在方法执行的前、后还是环绕时运行。
  4. Spring 织入:Spring 启动,创建代理对象,收工!

proxy

Spring AOP 默认使用标准的 JDK 动态代理作为 AOP 代理,默认情况下,如果业务对象未实现接口,则使用 CGLIB