AOP(面向切面编程)在 Spring 中是通过动态代理技术实现的,核心原理就是:在不修改原始代码的前提下,给方法的执行过程“加东西”(比如加日志、加权限、加事务等)。
💡 一句话理解 Spring AOP 的底层原理:
Spring 会在你调用目标方法前后插入你定义的“切面逻辑”,而这背后用的是代理对象来“包裹”你原来的对象。
🧱 两种底层实现方式
Spring AOP 使用的代理技术主要有两种方式:
技术 | 使用条件 | 原理说明 |
---|---|---|
JDK 动态代理 | 如果目标对象实现了接口 | 基于 java.lang.reflect.Proxy ,生成实现了相同接口的代理类 |
CGLIB 动态代理 | 如果目标对象没有实现接口 | 基于继承方式,用 ASM 字节码技术生成子类并重写方法 |
🔍 具体流程(你可以理解为“包裹”过程)
以调用一个 userService.saveUser()
为例,如果它被一个日志切面拦截了,底层流程是这样的:
-
Spring 启动时,扫描到你的切面类(带有
@Aspect
注解的类),并分析切点表达式。 -
为目标类(userService)创建代理对象,这个代理对象会代替原来的对象暴露在外部。
-
当你调用
userService.saveUser()
时,其实调用的是代理对象的方法。 -
代理对象:
-
先执行前置通知(
@Before
) -
调用原始的
saveUser()
方法 -
执行后置通知(
@After
、@AfterReturning
、@AfterThrowing
)
-
🧪 举个例子:
比如你有如下切面:
@Aspect
@Component
public class LogAspect {
@Before("execution(* com.example.service.*.*(..))")
public void beforeMethod() {
System.out.println("执行方法前记录日志");
}
}
调用 userService.addUser()
时,Spring 实际是这样执行的:
userServiceProxy.addUser() {
// AOP逻辑前置
logAspect.beforeMethod();
// 调用目标方法
realUserService.addUser();
// AOP逻辑后置(如果有)
}
🧠 总结底层核心
模块 | 说明 |
---|---|
切点表达式解析 | 识别哪些类、哪些方法需要织入逻辑 |
代理对象生成 | 使用 JDK 或 CGLIB 创建代理 |
方法调用时 | 拦截方法调用,执行增强逻辑 |
动态织入 | 所有切面逻辑在运行时动态织入,而不是编译时写死 |
⚠️ 注意:
-
Spring AOP 是 运行时 AOP(基于代理),不是编译时 AOP(如 AspectJ 编译器)
-
默认是基于 代理方式实现方法级别拦截,不支持字段级别、构造函数拦截(这是 AspectJ 的强项)