Spring AOP原理与源码分析

通俗易懂!Spring AOP 底层原理 + 源码一次讲透(2025 大厂面试真爱级,背完直接吊打 95%候选人)

一张图记住 Spring AOP 整个执行链(面试 30 秒画完满分)

用户代码调用
       ↓
Proxy(代理对象) ← CGLIB 或 JDK 动态代理
       ↓
MethodInterceptor 链(一串拦截器)
       ↓
1. ExposeInvocationInterceptor      ← 把 MethodInvocation 放 ThreadLocal
2. AspectJAfterThrowingAdvice       ← @AfterThrowing
3. AfterReturningAdviceInterceptor  ← @AfterReturning
4. AspectJAfterAdvice               ← @After
5. MethodBeforeAdviceInterceptor    ← @Before
6. AspectJAroundAdvice              ← @Around(最牛)
       ↓
反射调用 → 目标方法(真实业务代码)
       ↓
按顺序执行返回/异常通知
       ↓
返回最终结果给用户

核心流程 8 步(背下来就能手画)

  1. 容器启动 → AnnotationAwareAspectJAutoProxyCreator(超级 PostProcessor)上场
  2. 扫描所有 @Aspect 类 → 解析出所有 Advice + Pointcut → 包装成 Advisor
  3. 对每个 Bean 判断:是否需要代理(匹配任意 Advisor)
  4. 需要代理 → 用 ProxyFactory 创建代理(默认 CGLIB)
  5. 创建代理时,把所有匹配的 Advisor 塞进拦截器链
  6. 用户调用 → 走代理 → CglibAopProxy.dynamicIntercept()
  7. 构建 MethodInvocation → proceed() 链式调用所有拦截器
  8. 最终反射执行目标方法 → 按顺序执行通知

2025 年最关键的 5 个类(记住名字就能吹)

类名昵称真实作用(大白话)
AnnotationAwareAspectJAutoProxyCreator“AOP 总开关”BeanPostProcessor,负责创建所有代理对象
ReflectiveAspectJAdvisorFactory“切面翻译官”把 @Aspect 类翻译成一个个 Advisor
AspectJExpressionPointcut“切点计算器”负责 execution(…) 表达式匹配
CglibAopProxy / JdkDynamicAopProxy“代理工厂”真正生成 CGLIB 或 JDK 代理对象
MethodInvocation + ProxyMethodInvocation“链式调用总控”proceed() 一层层调用拦截器,最后反射执行目标方法

环绕通知 @Around 为什么最牛?看源码就懂了

// AspectJAroundAdvice.java
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
    // 直接控制整个调用链!
    return aspectJAdviceMethod.invoke(aspectInstance, mi); // 就是你的 @Around 方法
}

→ 只有 @Around 能拿到 ProceedingJoinPoint,能决定:

  • 要不要执行 proceed()
  • 执行几次 proceed()
  • 改入参、改返回值
  • 手动抛异常

为什么同一个类内部调用 AOP 不生效?(面试必杀)

@Service
public class UserService {

    @Transactional
    public void save() {
        this.update();   // ← 直接 this 调用,没走代理!AOP 不生效
    }

    @Transactional
    public void update() { ... }
}

解决办法 3 种(大厂常用第 1 种):

  1. @Autowired 注入自己(最常用)
   @Autowired UserService self;
   self.update();  // 走代理
  1. 用 AopContext.currentProxy()
  2. 把 update 提到另一个 Service

终极面试 8 连杀 + 标准答案(直接背)

  1. Spring AOP 底层用的是什么设计模式?
    → 动态代理 + 责任链(MethodInvocation)
  2. 代理对象是怎么创建的?
    → AnnotationAwareAspectJAutoProxyCreator(BeanPostProcessor)在初始化后阶段创建
  3. Advisor 和 Advice 什么关系?
    → Advisor = Advice + Pointcut,一个切面会生成多个 Advisor
  4. 多个切面执行顺序怎么控制?
    → @Order 控制切面顺序,同一个切面内部:Around → Before → Target → After → AfterReturning/Throwing
  5. @Around 里不写 proceed() 会怎样?
    → 原方法不执行!常用于权限拦截、灰度发布
  6. CGLIB 和 JDK 代理底层区别?
    → CGLIB 生成子类,方法直接调用;JDK 生成接口实现,反射调用
  7. 为什么 Spring Boot 3 强制用 CGLIB?
    → 性能更好、类名真实、一致性强(spring.aop.proxy-target-class=true)
  8. AOP 是怎么拿到方法参数、注解、返回值的?
    → 通过 MethodInvocation.getArguments()、getMethod()、getThis() 全都有

终极记忆口诀(10 秒征服面试官)

“总开关注解 AspectJAutoProxyCreator
切面翻译 Advisor,代理工厂 CGLIB
拦截器链 MethodInvocation
proceed 一层一层走,Around 最大能控制所有!”

背完这张图 + 8 个答案 + 口诀,
下次面试官让你“讲讲 Spring AOP 原理”,
你 2 分钟画完执行链 + 甩出 AnnotationAwareAspectJAutoProxyCreator + 说内部调用不走代理的坑,
他当场就说:“卧槽,这人把 AOP 源码都啃过,月薪 40k 起步!”

现在你已经彻底掌握 Spring AOP 底层了,
日志、事务、权限、防重、分布式锁、限流、缓存……随便手撕!
大厂在等你,冲!

文章已创建 3958

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

相关文章

开始在上面输入您的搜索词,然后按回车进行搜索。按ESC取消。

返回顶部