Spring AOP 核心概念:切面、通知、切点、织入

提到 Spring,就绕不开 AOP;提到 AOP,很多同学都会被「切面、通知、切点、织入」这四个核心概念搞懵,觉得抽象难理解,甚至越学越乱。

其实 AOP 一点都不复杂,它的核心就是「在不修改原有代码的前提下,对代码进行增强」------比如统一日志打印、接口权限校验、异常统一处理,这些都是 AOP 的典型应用。

什么是 Spring AOP?

AOP 全称 Aspect Oriented Programming,即「面向切面编程」,是 Spring 两大核心特性之一(另一个是 IOC)。

通俗来讲,AOP 就像「给代码"戴帽子"」:原有业务代码(比如用户登录、订单支付)是核心,我们不需要修改这些核心代码,只需要在代码执行的某个节点(比如执行前、执行后),动态添加一些通用功能(比如日志、权限校验)------这些通用功能就像"帽子",戴在核心代码上,不影响核心逻辑,还能实现功能复用。

举个最直观的例子:一个电商系统的「订单支付接口」,核心逻辑是"扣减库存、扣减余额";而我们需要在支付前校验用户权限,支付后打印操作日志、记录支付记录。这些"权限校验、日志打印"就是 AOP 要做的事,无需修改支付接口的核心代码,就能完成增强。

而「切面、通知、切点、织入」,就是实现这种"动态增强"的四大核心组件,各司其职、协同工作。

四大概念

我们用「学校保安站岗」来类比四大概念,帮你快速理解:

学校的「教学活动」(比如上课、考试)是核心业务;保安的「站岗、登记、巡逻」是通用功能,不影响教学,但能保障校园安全------保安的工作,就相当于 AOP 的增强逻辑;而保安如何安排站岗(什么时候站、在哪个门口站、怎么站),就对应 AOP 四大概念。

一、切点(Pointcut):"在哪里增强"------精准定位增强位置

切点就是「明确增强的位置」,相当于保安的「站岗地点」(比如学校正门、侧门),只有经过这些地点的人(对应代码中的方法),才会被增强(被保安登记)。

在 Spring AOP 中,切点的核心作用是:通过表达式,精准匹配需要被增强的方法,过滤掉不需要增强的方法,避免"无差别增强"。

示例

比如我们要给「所有订单相关的接口」添加日志增强,那么"所有订单相关的方法"就是切点;再比如,只给「支付接口(payOrder)」添加权限校验,那么"payOrder 方法"就是切点。

Spring AOP 常用切点表达式:

go 复制代码
// 1. 匹配指定包下的所有方法(最常用)
execution(* com.example.demo.service.*.*(..)) 
// 解读:com.example.demo.service 包下的所有类、所有方法,无论返回值、参数是什么

// 2. 匹配指定类的所有方法
execution(* com.example.demo.service.OrderService.*(..))

// 3. 匹配指定方法(精准匹配)
execution(* com.example.demo.service.OrderService.payOrder(..))

关键点:切点只负责「定位位置」,不负责「做什么增强」。

二、通知(Advice):"增强做什么"------定义增强逻辑

通知就是「增强的具体逻辑」,相当于保安的「具体工作内容」(比如登记身份、测量体温),明确在切点位置,要做什么事。

在 Spring AOP 中,通知的核心作用是:定义在切点方法执行的某个时机,执行什么样的增强逻辑,是 AOP 增强的"具体实现"。

Spring AOP 5种通知类型

通知的核心区别,在于「执行时机不同」,结合实战场景理解,不用死记硬背:

    1. 前置通知(@Before):切点方法执行「之前」执行,比如接口执行前的权限校验、参数校验;
    1. 后置通知(@After):切点方法执行「之后」执行(无论是否抛出异常),比如接口执行后的日志记录、资源释放;
    1. 返回通知(@AfterReturning):切点方法「正常执行完成后」执行,比如获取接口返回结果,做后续处理;
    1. 异常通知(@AfterThrowing):切点方法「抛出异常后」执行,比如异常捕获、日志记录、报警;
    1. 环绕通知(@Around):包裹切点方法,可在方法执行前、执行后、异常时做处理,功能最强大(实战中最常用)。
示例

比如给支付接口(payOrder)添加增强:

  • • 前置通知:校验用户是否登录、是否有支付权限;

  • • 返回通知:支付成功后,记录支付金额、订单号,同步到消息队列;

  • • 异常通知:支付失败(比如余额不足),捕获异常,记录错误日志,提示用户。

三、切面(Aspect):"把增强和位置绑定"------整合切点和通知

切面就是「把切点和通知绑定在一起」,相当于「保安的工作安排」:明确"在哪个门口(切点),做什么工作(通知)",是 AOP 的核心组件,将分散的增强逻辑和定位规则整合起来。

在 Spring AOP 中,切面的核心作用是:封装切点和通知,形成一个独立的模块,实现增强逻辑的复用(比如一个切面可以绑定多个切点和通知,实现全局日志增强)。

简单说:切面 = 切点 + 通知,没有切面,切点和通知就是孤立的,无法完成增强。

示例

我们创建一个「日志切面」,绑定切点和通知,实现全局接口日志增强:

go 复制代码
// 用 @Aspect 注解标记此类为切面
@Aspect
@Component // 交给 Spring 管理
public class LogAspect {
    // 1. 定义切点:匹配所有 service 包下的方法
    @Pointcut("execution(* com.example.demo.service.*.*(..))")
    public void logPointcut() {} // 切点方法,无实际逻辑,仅用于标记
    
    // 2. 定义通知:前置通知,在切点方法执行前执行
    @Before("logPointcut()")
    public void beforeLog(JoinPoint joinPoint) {
        // 增强逻辑:打印请求方法名、参数
        String methodName = joinPoint.getSignature().getName();
        Object[] args = joinPoint.getArgs();
        System.out.println("前置通知:执行方法:" + methodName + ",参数:" + Arrays.toString(args));
    }
    
    // 3. 定义通知:后置通知,在切点方法执行后执行
    @After("logPointcut()")
    public void afterLog() {
        System.out.println("后置通知:方法执行完成");
    }
}

解读:这个 LogAspect 就是一个切面,logPointcut() 是切点(定位所有 service 方法),beforeLog 和 afterLog 是通知(定义日志增强逻辑),两者通过注解绑定,实现全局日志增强。

四、织入(Weaving):"何时增强"------将切面应用到目标对象的过程

织入就是「把切面的增强逻辑,动态添加到目标对象(核心业务代码)的过程」,相当于「保安到岗执行工作」的过程------把"站岗安排(切面)"落地到实际场景中。

在 Spring AOP 中,织入的核心作用是:将切面的增强逻辑,在指定时机(编译期、类加载期、运行期)融入到目标对象的方法中,完成动态增强,且不修改目标对象的原有代码。

Spring AOP 织入时机

Spring AOP 采用「运行期织入」(最灵活,也是实战中唯一使用的方式):

  • • 编译期织入:在代码编译时,将增强逻辑融入目标类(需要特殊编译器,不常用);

  • • 类加载期织入:在目标类加载到 JVM 时,将增强逻辑融入(需要自定义类加载器,较少用);

  • • 运行期织入:在程序运行时,通过 Spring 动态代理(JDK 动态代理、CGLIB 代理),动态生成目标对象的代理对象,将切面增强逻辑融入代理对象中------无需修改原有代码,灵活高效,Spring 默认采用这种方式。

示例

当我们启动 Spring 项目时,Spring 会自动扫描 @Aspect 标记的切面,通过动态代理,将切面中的增强逻辑(通知),织入到切点匹配的方法中。比如我们调用 OrderService 的 payOrder 方法时,Spring 会生成 OrderService 的代理对象,先执行前置通知(权限校验),再执行 payOrder 核心逻辑,最后执行后置通知(日志记录)------这个"动态代理+增强逻辑融入"的过程,就是织入。

四大概念的关系

用一句话总结四大概念的协同关系:通过「织入」过程,将「切面」(包含「切点」和「通知」)动态应用到目标对象,实现不修改核心代码的增强

    1. 切点:定位"要增强的方法"(在哪里加);
    1. 通知:定义"增强的逻辑"(加什么);
    1. 切面:绑定切点和通知(把"在哪里加"和"加什么"整合);
    1. 织入:将切面的增强逻辑,动态融入目标方法(怎么加,何时加)。

注意事项

混淆切点和通知

❌ 错误认知:以为切点就是增强逻辑;

✅ 正确区分:切点只负责"定位位置",通知负责"执行逻辑",两者必须绑定在切面中,才能实现增强。

忘记给切面加 @Component 注解

❌ 错误做法:只加 @Aspect 标记切面,忘记加 @Component;

✅ 正确做法:@Aspect 只是标记此类是切面,必须加 @Component 交给 Spring 管理,Spring 才能扫描到切面,完成织入。

文末小结

其实 Spring AOP 四大核心概念,本质就是"分工协作":切点找位置、通知做事情、切面整合成模块、织入落地执行,最终实现"无侵入式增强"。

同学们在学习时,不用死记硬背术语,结合「保安站岗」的类比,再对照实战案例,就能快速理解;后续学习 AOP 实战(比如全局日志、权限校验),再回头看这四个概念,会发现一切都很简单。

如果你在学习 AOP 时遇到过困惑,或者有更好的理解方法,欢迎在评论区留言交流,一起避坑、一起进步!

别忘了点赞+在看+收藏三连,关注我,解锁更多 Spring 实战干货,下期再见❤️

相关推荐
Rust研习社19 小时前
组合真的优于继承吗?为什么 Rust 和 Go 都拥抱组合舍弃继承?
后端·rust·编程语言
IT_陈寒19 小时前
JavaScript的闭包把我坑惨了,说好的内存会自动回收呢?
前端·人工智能·后端
CaffeinePro20 小时前
Pydantic深度使用:数据校验、枚举、ORM映射
后端·fastapi
Chenyiax20 小时前
从 Chat 到 Responses:OpenAI API 抽象为什么变了?
后端
MariaH20 小时前
Koa和Express的区别
后端
MariaH20 小时前
Koa框架的使用
后端
luckdewei1 天前
那个用 passlib 做认证的新同事,上线第一天就把用户密码写进了日志
后端
ping某1 天前
为什么 Nginx 明明监听了 80,转发后端时却用了 4xxxx 端口?
后端·nginx
JustHappy1 天前
我汇总了身边朋友的经历才发现,其实第一份实习是最难找的......
前端·后端·面试
uhakadotcom1 天前
在python 的 工程化架构中 ,什么是 薄包装器层?
后端·面试·github