Spring AOP(面向切面编程)的底层实现主要基于动态代理技术,具体实现方式取决于目标对象是否实现了接口。下面详细分析其核心原理:
1. 两种代理机制
(1) JDK 动态代理(基于接口)
- 适用场景:目标类实现了至少一个接口
- 实现原理:
- 通过java.lang.reflect.Proxy类创建代理对象
- 在运行时动态生成实现了目标接口的代理类
- 内部使用InvocationHandler处理所有方法调用
- 示例代码:
- java
Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 前置增强
Object result = method.invoke(target, args);
// 后置增强
return result;
}
});
(2) CGLIB 动态代理(基于子类)
- 适用场景:目标类没有实现任何接口
- 实现原理:
- 通过继承目标类创建子类代理
- 使用ASM字节码操作框架生成子类
- 重写父类方法并加入增强逻辑
- 需要目标类和方法不是final的
- 核心类:MethodInterceptor接口
2. AOP 核心工作流程
- 解析切面配置:读取@Aspect注解和各类通知注解(@Before、@After等)
- 创建代理对象:
- 根据目标对象选择JDK或CGLIB代理
- 生成代理类字节码
- 方法调用拦截:
- 代理对象拦截所有方法调用
- 根据Pointcut表达式匹配需要增强的方法
- 执行通知链:
- 按顺序执行相关Advice(前置、后置、环绕等)
- 最终调用目标方法
3. 关键实现细节
(1) 代理对象创建时机
- 默认在第一次使用bean时创建(懒加载)
- 可通过@Scope配置改变创建时机
(2) 通知类型实现
- 前置通知:在invoke或intercept方法中先执行增强逻辑
- 后置通知:在try-finally块中执行
- 环绕通知:完全控制方法调用流程
- 异常通知:通过catch块实现
- 最终通知:在finally块中执行
(3) 责任链模式
多个通知会形成调用链,通过MethodInterceptor链式调用:
java
public class ReflectiveMethodInvocation implements ProxyMethodInvocation {
private final List<MethodInterceptor> interceptors;
private int currentInterceptorIndex = -1;
public Object proceed() throws Throwable {
if (this.currentInterceptorIndex == this.interceptors.size() - 1) {
return invokeJoinpoint();
}
MethodInterceptor interceptor =
this.interceptors.get(++this.currentInterceptorIndex);
return interceptor.invoke(this);
}
}
4. 性能考量
- 首次创建开销:
- JDK代理生成较快
- CGLIB首次生成较慢(需要生成字节码)
- 方法调用开销:
- JDK代理调用稍快
- CGLIB调用稍慢(需要走方法拦截)
- 优化策略:
- 对频繁调用的方法使用AOP要谨慎
- 可通过proxyTargetClass=true强制使用CGLIB
5. 与AspectJ的区别
特性 |
Spring AOP |
AspectJ |
实现方式 |
动态代理 |
编译时/加载时织入 |
性能 |
运行时开销较大 |
编译后无运行时开销 |
功能范围 |
仅支持方法级别的拦截 |
支持字段、构造器拦截等 |
依赖 |
仅需Spring核心 |
需要AspectJ编译器/织入器 |
Spring AOP的设计平衡了功能需求和易用性,虽然能力不如AspectJ全面,但足以满足大多数企业应用的需求,且与Spring容器无缝集成。
© 版权声明
文章版权归作者所有,未经允许请勿转载。如内容涉嫌侵权,请在本页底部进入<联系我们>进行举报投诉!
THE END
暂无评论内容