Spring AOP实现原理
AOP核心概念
核心概念解析
- Aspect(切面): 封装横切关注点的模块,包含多个 Advice 和 Pointcut,如日志切面、事务切面、权限校验切面。
- Join Point(连接点):程序执行过程中的一个点(如方法调用、异常抛出),可插入切面逻辑的位置。
- Advice(通知):在特定连接点执行的动作(如前置、后置、环绕处理),如记录方法执行时间、事务提交或回滚。
- Pointcut(切点):通过表达式匹配一组连接点,定义哪些连接点会被切面处理。
- Target Object(目标对象):被代理的原始对象(包含业务逻辑的 Bean)。
- Proxy(代理):由 Spring 生成的代理对象,包装目标对象以插入切面逻辑。
- Weaving(织入):将切面代码与目标对象关联的过程(编译时、类加载时或运行时)。
Advice(通知)类型
- @Before(前置通知):在目标方法执行前触发;适用于参数校验、权限控制。
- @After(后置通知):在目标方法执行后触发(无论是否抛出异常),适用于资源清理(如关闭文件流)。
- @AfterReturning(返回后通知):在目标方法 正常返回后 触发,可访问返回值。
- @AfterThrowing(异常通知):在目标方法 抛出异常后 触发,可捕获特定异常类型。
- @Around(环绕通知):包裹目标方法,控制其执行流程(类似过滤器),需手动调用
proceed()
执行目标方法。
Pointcut(切点)表达式
execution(* com.example.service.*.*(..)) |
匹配 com.example.service 包下所有类的所有方法 |
@annotation(com.example.anno.Log) |
匹配被 @Log 注解标记的方法 |
within(com.example.service.UserService) |
匹配 UserService 类中的所有方法 |
args(java.lang.String) |
匹配参数类型为 String 的方法 |
代理机制
- JDK 动态代理
- 条件:目标对象实现了至少一个接口。
- 原理:基于接口生成代理类,调用
InvocationHandler.invoke()
插入切面逻辑。
- CGLIB 动态代理
- 条件:目标对象未实现接口(或配置强制使用 CGLIB)。
- 原理:通过继承目标类生成子类代理,覆盖父类方法。
AOP 与 AspectJ 的关系
织入时机 | 运行时动态代理 | 编译时或类加载时(支持更丰富的连接点) |
性能 | 略低(运行时生成代理) | 更高(编译时优化) |
功能范围 | 仅支持方法级别的连接点 | 支持字段、构造器、静态代码块等连接点 |
使用场景 | 轻量级应用,无需复杂切面 | 企业级复杂切面需求(如性能监控、安全检查) |
JDK动态代理与CGLIB代理的底层实现
JDK 动态代理
-
核心原理
-
基于接口:要求目标对象必须实现至少一个接口。
-
反射机制:通过
java.lang.reflect.Proxy
和InvocationHandler
动态生成代理类。 -
代理对象行为:代理类实现目标接口,并将方法调用转发到
InvocationHandler
。
-
-
实现步骤
-
定义接口与实现类
public interface UserService { void saveUser(User user); } public class UserServiceImpl implements UserService { public void saveUser(User user) { /* 业务逻辑 */ } }
-
实现
InvocationHandler
public class JdkProxyHandler implements InvocationHandler { private Object target; // 目标对象 public JdkProxyHandler(Object target) { this.target = target; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // 前置增强 System.out.println("Before method: " + method.getName()); // 调用目标方法 Object result = method.invoke(target, args); // 后置增强 System.out.println("After method: " + method.getName()); return result; } }
-
生成代理对象
UserService target = new UserServiceImpl(); UserService proxy = (UserService) Proxy.newProxyInstance( target.getClass().getClassLoader(), target.getClass().getInterfaces(), // 必须为接口数组 new JdkProxyHandler(target) ); proxy.saveUser(new User()); // 调用代理方法
-
-
源码关键点
Proxy.newProxyInstance()
:动态生成代理类的字节码,其类名通常为$Proxy0
、$Proxy1
等。- 代理类结构:代理类继承
Proxy
并实现目标接口,所有方法调用均委托给InvocationHandler.invoke()
。
CGLIB 动态代理
-
核心原理
-
基于继承:通过生成目标类的子类作为代理类(即使目标类未实现接口)。
-
字节码操作:使用 ASM 库直接修改字节码,生成新类。
-
方法拦截:通过
MethodInterceptor
接口实现方法增强。
-
-
实现步骤
-
定义目标类
public class UserService { public void saveUser(User user) { /* 业务逻辑 */ } }
-
实现
MethodInterceptor
public class CglibMethodInterceptor implements MethodInterceptor { public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { // 前置增强 System.out.println("Before method: " + method.getName()); // 调用目标方法(通过 FastClass 机制,避免反射) Object result = proxy.invokeSuper(obj, args); // 后置增强 System.out.println("After method: " + method.getName()); return result; } }
-
生成代理对象
Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(UserService.class); // 设置父类 enhancer.setCallback(new CglibMethodInterceptor()); UserService proxy = (UserService) enhancer.create(); // 生成代理对象 proxy.saveUser(new User()); // 调用代理方法
-
-
源码关键点
- Enhancer 类:负责生成代理类的字节码。
- FastClass 机制:为代理类和目标类生成索引,直接通过索引调用方法,避免反射(性能优于 JDK 代理)。
- 代理类结构:代理类继承目标类,重写父类方法,并在方法中调用
MethodInterceptor.intercept()
。
JDK 代理与 CGLIB 代理对比
代理方式 | 基于接口 | 基于继承 |
目标类要求 | 必须实现接口 | 可为任意类(非 final) |
性能 | 生成快,调用慢(反射) | 生成慢,调用快(FastClass) |
方法覆盖 | 仅代理接口方法 | 代理所有非 final 方法 |
依赖 | 内置 JDK 支持 | 需引入 CGLIB 库(Spring 已默认包含) |
代理类名 | $Proxy0 、$Proxy1 |
UserService$$EnhancerByCGLIB$$12345678 |
Spring AOP 的代理选择策略
- 默认行为:若目标类实现接口 → 使用 JDK 动态代理;若目标类未实现接口 → 使用 CGLIB 动态代理。
- 强制使用 CGLIB:通过
@EnableAspectJAutoProxy(proxyTargetClass = true)
配置,强制对所有类使用 CGLIB。 - 排除 final 方法:CGLIB 无法代理
final
方法,需确保目标方法可被重写。
代理对象的生成流程
核心类与接口
- ProxyFactory
- 作用:代理对象的配置工厂,用于设置目标对象、切面(Advisor)、通知(Advice)等。
- 继承关系:
ProxyFactory
→ProxyCreatorSupport
→AdvisedSupport
。
- AopProxy
- 接口:定义代理对象的生成方法
getProxy()
。 - JdkDynamicAopProxy:基于 JDK 动态代理实现。
- ObjenesisCglibAopProxy:基于 CGLIB 动态代理实现(Spring 优化后的版本)。
- 接口:定义代理对象的生成方法
- AdvisedSupport:封装代理配置信息(目标对象、切面列表、代理接口等),供
AopProxy
使用。
代理生成流程
-
配置阶段(ProxyFactory 初始化):开发者通过
ProxyFactory
设置代理所需的元数据。// 1. 创建ProxyFactory并配置 ProxyFactory proxyFactory = new ProxyFactory(); proxyFactory.setTarget(new UserServiceImpl()); // 目标对象 proxyFactory.addAdvice(new LoggingAdvice()); // 添加通知(Advice) proxyFactory.setInterfaces(UserService.class); // 指定代理接口(可选) // 2. 生成代理对象 UserService proxy = (UserService) proxyFactory.getProxy();
-
代理生成阶段(AopProxy 创建代理):选择代理策略(JDK或CGLIB)、创建AopProxy实例、生成代理对象。
通知(Advice)的执行链路
责任链模式的核心思想
- 定义:将多个处理器(拦截器)按顺序连接成链,每个处理器决定是否将请求传递给下一个处理器。
- 优点:解耦处理器之间的依赖,支持动态扩展处理逻辑。
- 在 Spring AOP 中的应用:将多个通知(如
@Around
)转换为拦截器(MethodInterceptor
),形成链式结构,按顺序执行。
拦截器链的构建
- 拦截器链的组成:每个
Advisor
(切面) 会被适配为一个MethodInterceptor
(方法拦截器)。 - 链的构建过程:Spring 在创建代理对象时,将所有
Advisor
转换为MethodInterceptor
,并按优先级排序,形成拦截器链。
拦截器链执行流程
+---------------------+
| MethodInvocation |
| (ReflectiveMethod) |
+----------+----------+
| proceed()
v
+----------------+ +----------------+ +----------------+ +----------------+
| Interceptor 1 | --> | Interceptor 2 | --> | Interceptor 3 | --> | Target Method |
| (@Before) | | (@Around) | | (@After) | | |
+----------------+ +----------------+ +----------------+ +----------------+
AspectJ注解驱动的AOP解析过程
切面类的识别与注册
- @Aspect注解:标记一个类为切面。
- @Component或@Bean:确保切面类被Spring容器管理。
- AnnotationAwareAspectJAutoProxyCreator:继承自
AbstractAutoProxyCreator
的后置处理器,负责初始化后生成Proxy。
切点表达式解析与匹配
- AspectJExpressionPointcut:封装AspectJ切点表达式,实现
Pointcut
接口的getClassFilter()
和getMethodMatcher()
。 - 表达式解析:使用AspectJ的
PointcutParser
将字符串表达式转换为抽象语法树(AST)。 - 匹配逻辑:在运行时检查目标类和方法是否匹配切点表达式。
通知方法适配为Advice
@Before | MethodBeforeAdvice |
AspectJMethodBeforeAdvice |
@After | AfterAdvice |
AspectJAfterAdvice |
@AfterReturning | AfterReturningAdvice |
AspectJAfterReturningAdvice |
@AfterThrowing | ThrowsAdvice |
AspectJAfterThrowingAdvice |
@Around | MethodInterceptor |
AspectJAroundAdvice |
构建Advisor并整合到代理
- 收集Advisor:在
AnnotationAwareAspectJAutoProxyCreator
中,查找所有切面类的Advisor。 - 匹配目标Bean:判断当前Bean是否需要被代理(即是否存在匹配的Advisor)。
- 生成代理对象:根据配置(JDK或CGLIB)生成代理对象,并将Advisor转换为拦截器链。
动态代理生成与拦截链执行
- 代理对象调用方法:代理对象拦截目标方法调用。
- 构建拦截器链:所有匹配的
Advisor
转换为MethodInterceptor
,按优先级排序。 - 链式执行:通过
ReflectiveMethodInvocation
递归调用拦截器,直至执行目标方法。