一、什么是 AOP?
AOP = Aspect Oriented Programming(面向切面编程)
核心作用:
👉 把“公共逻辑”从业务代码中剥离出来,统一管理。
比如:
- 日志记录
- 事务控制
- 权限校验
- 性能监控
- 接口限流
二、Spring AOP 底层原理
Spring AOP 只有一个核心:
动态代理
Spring 在运行时生成代理对象。
三、两种代理方式(重点🔥)
1️⃣ JDK 动态代理(默认)
- 目标类必须实现接口
- 基于
java.lang.reflect.Proxy
原理:
接口 → 生成代理类 → 方法调用被拦截
示意图:
Controller
↓
Proxy (代理对象)
↓
ServiceImpl
2️⃣ CGLIB 动态代理
- 目标类没有接口时使用
- 基于继承
- 通过字节码增强
原理:
生成一个子类
重写方法
在方法前后加增强逻辑
四、Spring AOP 执行流程
以 @Transactional 为例:
步骤 1️⃣ Bean 初始化
Spring 在创建 Bean 时会检查:
是否有 AOP 注解?
如果有:
创建代理对象
步骤 2️⃣ 方法调用
你调用:
userService.save();
实际上调用的是:
Proxy.save();
步骤 3️⃣ 代理内部执行
伪代码:
before(); // 开启事务
target.save(); // 执行真实方法
after(); // 提交事务
如果异常:
rollback();
五、Spring AOP 关键概念
| 名词 | 解释 |
|---|---|
| Aspect | 切面 |
| Advice | 通知(增强逻辑) |
| JoinPoint | 连接点(方法) |
| Pointcut | 切入点(哪些方法) |
| Weaving | 织入 |
六、五种通知类型
@Before
@After
@AfterReturning
@AfterThrowing
@Around // 最强
🔥 @Around 最重要
@Around("execution(* com.example.service.*.*(..))")
public Object around(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("前置");
Object result = pjp.proceed();
System.out.println("后置");
return result;
}
七、底层源码关键类(面试加分🔥)
| 类 | 作用 |
|---|---|
| ProxyFactory | 创建代理 |
| JdkDynamicAopProxy | JDK代理 |
| CglibAopProxy | CGLIB代理 |
| Advisor | 封装切面 |
| MethodInterceptor | 方法拦截器 |
八、Spring AOP 和 AspectJ 区别
| Spring AOP | AspectJ | |
|---|---|---|
| 原理 | 动态代理 | 字节码修改 |
| 织入时机 | 运行时 | 编译时 |
| 性能 | 较低 | 更高 |
| 功能 | 只支持方法级别 | 支持字段/构造器 |
九、常见面试追问
1️⃣ 为什么同类方法调用事务失效?
this.save(); // 失效
因为:
AOP 是代理对象生效,this 调用绕过代理。
2️⃣ 为什么 private 方法事务不生效?
因为:
CGLIB 通过重写方法实现增强,private 无法被重写。
3️⃣ Spring 默认用哪种代理?
- 有接口 → JDK
- 没接口 → CGLIB
- Spring Boot 2+ 默认强制 CGLIB
十、完整面试回答模板(直接背🔥)
Spring AOP 的底层原理是基于动态代理实现的。
如果目标类实现接口,则使用 JDK 动态代理;
如果没有接口,则使用 CGLIB 通过继承生成子类。在 Bean 初始化阶段,Spring 会为需要增强的类创建代理对象。
方法调用时,实际上调用的是代理对象,代理对象内部通过 MethodInterceptor 在方法执行前后织入增强逻辑,比如事务、日志等。Spring AOP 属于运行时织入,而 AspectJ 属于编译时织入。
十一、画个底层结构图
Client
↓
Proxy (代理对象)
↓
MethodInterceptor
↓
Target Object