Spring AOP 核心:七大概念、代理选型与失效场景

spring 📚 learning spring-aop-core · spring · aop · proxy · cglib · jdk-dynamic-proxy · pointcut

TL;DR(30 秒扫完)

  • AOP 本质:基于代理的切面编程增强,在方法前后织入横切逻辑
  • 七大核心概念:JoinPoint / Pointcut / Advice / Aspect / Target / Introduction / Weaving
  • 代理选型:Spring 5+ 默认有接口用 JDK、无接口用 CGLIB;Spring Boot 2.x 默认 spring.aop.proxy-target-class=true 强制 CGLIB
  • 五大失效场景:自调用、private/final/static 方法、非 public、未注册 Bean、切面未扫描

关键结论

结论 A(七大概念)JoinPoint(连接点)/ Pointcut(切点)/ Advice(通知)/ Aspect(切面)/ Target(目标)/ Introduction(引入)/ Weaving(织入)
结论 B(代理选型)JDK 代理基于接口,CGLIB 基于继承;Spring 5+ 默认有接口用 JDK 无接口用 CGLIB
结论 C(Spring Boot 2.x)默认 spring.aop.proxy-target-class=true 强制 CGLIB
结论 D(五大失效场景)自调用、private/final/static 方法、非 public、未注册 Bean、切面未扫描

完整讲解(费曼四步)

STEP 1 · 概念(一句话定义)

  • AOP(面向切面编程):基于代理的切面编程增强,在方法前后织入横切逻辑(如日志、事务、权限)
  • 切面(Aspect):横切关注点的模块化(如日志切面、事务切面)
  • 通知(Advice):在连接点执行的动作(前置、后置、环绕、异常)

STEP 2 · 大白话(生活类比)

类比(AOP):就像快递公司的"签收流程"——你在收快递时(方法执行),快递员会自动记录签收时间(前置通知)、拍照留证(后置通知)、异常时上报(异常通知),整个过程你不需要参与(切面逻辑与业务逻辑解耦)。

STEP 3 · 底层(细节 + 代码/表格)

3.1 七大核心概念

概念定义示例
JoinPoint程序执行的某个点(方法执行)一个方法执行就是一个 JoinPoint
Pointcut定义哪些 JoinPoint 需要织入execution( com.example.service..*(..))
Advice在 JoinPoint 执行的动作@Before / @After / @Around / @AfterThrowing
Aspect切面 = 切点 + 通知一个类标注 @Aspect
Target被代理的目标对象被 @Aspect 增强的类
Introduction给目标类添加新的接口/属性Spring AOP 不支持
Weaving将切面织入到目标对象的过程运行时织入(Spring AOP)vs 编译期织入(AspectJ)

3.2 代理选型

特性JDK 动态代理CGLIB
原理基于接口生成代理类基于继承生成子类
要求目标类必须实现接口目标类不能是 final
性能略快略慢(生成子类有开销)
Spring 5+ 默认有接口用 JDK无接口用 CGLIB
Spring Boot 2.x默认关闭默认 spring.aop.proxy-target-class=true 强制 CGLIB
为什么 Spring Boot 2.x 强制 CGLIB?
  • 因为 Spring Boot 2.x 默认使用 @EnableAspectJAutoProxy(proxyTargetClass = true)
  • 这样即使目标类有接口,也使用 CGLIB 代理,避免类型转换问题

3.3 切点表达式

表达式含义示例
execution匹配方法执行execution( com.example.service..*(..))
@within匹配标注了某注解的类@within(com.example.annotation.Log)
@annotation匹配标注了某注解的方法@annotation(org.springframework.web.bind.annotation.GetMapping)
@args匹配参数类型@args(java.lang.String)

3.4 五大失效场景

失效场景原因规避方案
自调用类内部方法调用不经过代理注入自身代理(@Lazy / @Resource 注入自己)
private/final/static 方法CGLIB 无法继承 final 类,JDK 代理不处理非 public 方法方法改为 public、非 final
非 public 方法JDK 代理只处理 public 方法方法改为 public
未注册 BeanAOP 代理只在 Spring 容器中生效确保目标类被 @Component 标注
切面未扫描@Aspect 类未被 Spring 扫描确保 @Aspect 类在 @ComponentScan 范围内

3.5 自调用的 4 种规避方案

  • 注入自身代理:
  • ```java @Service public class ServiceA { @Autowired @Lazy private ServiceA self; public void methodA() { self.methodB(); // 经过代理 } @Transactional public void methodB() { ... } } ```
  • AopContext.currentProxy():
  • ```java ((ServiceA) AopContext.currentProxy()).methodB(); ``` (需要 @EnableAspectJAutoProxy(exposeProxy = true))
  • 反射调用:
  • ```java Method method = getClass().getMethod("methodB"); method.invoke(getAopProxy(), args); ```
  • 拆分成两个类:
  • ```java @Service public class ServiceA { @Autowired private ServiceB serviceB; public void methodA() { serviceB.methodB(); // 经过代理 } } @Service public class ServiceB { @Transactional public void methodB() { ... } } ```

    STEP 4 · 简化(比喻/口诀)

    AOP 七大概念口诀:连接点、切点、通知、切面、目标、引入、织入(7 个概念记 7 个字)。
    代理选型口诀:有接口用 JDK,无接口用 CGLIB;Spring Boot 2.x 强制 CGLIB。
    五大失效口诀:自调用、非 public、final/static、未注册、未扫描(5 个场景记 5 个字)。

    速查表

    AOP 七大概念 · 连接点/切点/通知/切面/目标/引入/织入
    代理选型 · 有接口用 JDK 无接口用 CGLIB · Spring Boot 2.x 强制 CGLIB
    切点表达式 · execution/@within/@annotation/@args
    五大失效 · 自调用/非public/final-static/未注册/未扫描
    自调用规避 · 注入自身代理/AopContext/反射/拆分两类
    常见错点:Spring AOP 编译期织入 ❌ / 自调用不影响 AOP ❌ / Spring Boot 2.x 用 JDK 代理 ❌

    Anki 候选卡片

    Q: Spring AOP 的七大核心概念是什么?
    A: JoinPoint / Pointcut / Advice / Aspect / Target / Introduction / Weaving
    Q: JDK 代理和 CGLIB 的区别是什么?
    A: JDK 基于接口,CGLIB 基于继承;JDK 要求目标类实现接口,CGLIB 要求目标类不能是 final
    Q: Spring Boot 2.x 默认使用哪种代理?
    A: 默认 spring.aop.proxy-target-class=true 强制 CGLIB
    Q: Spring AOP 的五大失效场景是什么?
    A: 自调用、private/final/static 方法、非 public、未注册 Bean、切面未扫描
    Q: 自调用导致 AOP 失效的 4 种规避方案是什么?
    A: 注入自身代理(@Lazy / @Resource)、AopContext.currentProxy()、反射调用、拆分成两个类
    Q: 切点表达式的 4 种类型是什么?
    A: execution / @within / @annotation / @args
    Q: Spring AOP 和 AspectJ 的区别是什么?
    A: Spring AOP 是运行时织入,AspectJ 是编译期/加载期织入;AspectJ 支持更多织入点

    关联题目

  • [ ] 《介绍一下 Spring 的 AOP》—— 2026-09-28 Round 1, 评分 ⭐⭐⭐
  • 关联知识

    AOP 七大核心概念、JDK/CGLIB 代理选型、五大失效场景与规避方案
    ✦ 记 忆 口 诀 ✦
    七大概念七字记 / 有接口用 JDK 无接口用 CGLIB / 五大失效场景
    关键可视化
    暂无可视化
    知识关系

    ⬆️ 前置(Prerequisite)

    spring-ioc-core

    🔄 延伸(Extends)

    暂无

    ⚡ 对比(Contrast)

    暂无
    🎯 概念 📏 规则 ⚠️ 误区 🔍 追问 ✨ 口诀 共 0 张卡,点击翻面