通俗易懂!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 步(背下来就能手画)
- 容器启动 → AnnotationAwareAspectJAutoProxyCreator(超级 PostProcessor)上场
- 扫描所有 @Aspect 类 → 解析出所有 Advice + Pointcut → 包装成 Advisor
- 对每个 Bean 判断:是否需要代理(匹配任意 Advisor)
- 需要代理 → 用 ProxyFactory 创建代理(默认 CGLIB)
- 创建代理时,把所有匹配的 Advisor 塞进拦截器链
- 用户调用 → 走代理 → CglibAopProxy.dynamicIntercept()
- 构建 MethodInvocation → proceed() 链式调用所有拦截器
- 最终反射执行目标方法 → 按顺序执行通知
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 种):
- @Autowired 注入自己(最常用)
@Autowired UserService self;
self.update(); // 走代理
- 用 AopContext.currentProxy()
- 把 update 提到另一个 Service
终极面试 8 连杀 + 标准答案(直接背)
- Spring AOP 底层用的是什么设计模式?
→ 动态代理 + 责任链(MethodInvocation) - 代理对象是怎么创建的?
→ AnnotationAwareAspectJAutoProxyCreator(BeanPostProcessor)在初始化后阶段创建 - Advisor 和 Advice 什么关系?
→ Advisor = Advice + Pointcut,一个切面会生成多个 Advisor - 多个切面执行顺序怎么控制?
→ @Order 控制切面顺序,同一个切面内部:Around → Before → Target → After → AfterReturning/Throwing - @Around 里不写 proceed() 会怎样?
→ 原方法不执行!常用于权限拦截、灰度发布 - CGLIB 和 JDK 代理底层区别?
→ CGLIB 生成子类,方法直接调用;JDK 生成接口实现,反射调用 - 为什么 Spring Boot 3 强制用 CGLIB?
→ 性能更好、类名真实、一致性强(spring.aop.proxy-target-class=true) - AOP 是怎么拿到方法参数、注解、返回值的?
→ 通过 MethodInvocation.getArguments()、getMethod()、getThis() 全都有
终极记忆口诀(10 秒征服面试官)
“总开关注解 AspectJAutoProxyCreator
切面翻译 Advisor,代理工厂 CGLIB
拦截器链 MethodInvocation
proceed 一层一层走,Around 最大能控制所有!”
背完这张图 + 8 个答案 + 口诀,
下次面试官让你“讲讲 Spring AOP 原理”,
你 2 分钟画完执行链 + 甩出 AnnotationAwareAspectJAutoProxyCreator + 说内部调用不走代理的坑,
他当场就说:“卧槽,这人把 AOP 源码都啃过,月薪 40k 起步!”
现在你已经彻底掌握 Spring AOP 底层了,
日志、事务、权限、防重、分布式锁、限流、缓存……随便手撕!
大厂在等你,冲!