SpringAOP的底层原理

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 核心工作流程

  1. 解析切面配置:读取@Aspect注解和各类通知注解(@Before@After等)
  2. 创建代理对象
  3. 根据目标对象选择JDK或CGLIB代理
  4. 生成代理类字节码
  5. 方法调用拦截
  6. 代理对象拦截所有方法调用
  7. 根据Pointcut表达式匹配需要增强的方法
  8. 执行通知链
  9. 按顺序执行相关Advice(前置、后置、环绕等)
  10. 最终调用目标方法

3. 关键实现细节

(1) 代理对象创建时机

  • 默认在第一次使用bean时创建(懒加载)
  • 可通过@Scope配置改变创建时机

(2) 通知类型实现

  • 前置通知:在invokeintercept方法中先执行增强逻辑
  • 后置通知:在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. 性能考量

  1. 首次创建开销
  2. JDK代理生成较快
  3. CGLIB首次生成较慢(需要生成字节码)
  4. 方法调用开销
  5. JDK代理调用稍快
  6. CGLIB调用稍慢(需要走方法拦截)
  7. 优化策略
  8. 对频繁调用的方法使用AOP要谨慎
  9. 可通过proxyTargetClass=true强制使用CGLIB

5. 与AspectJ的区别

特性

Spring AOP

AspectJ

实现方式

动态代理

编译时/加载时织入

性能

运行时开销较大

编译后无运行时开销

功能范围

仅支持方法级别的拦截

支持字段、构造器拦截等

依赖

仅需Spring核心

需要AspectJ编译器/织入器

Spring AOP的设计平衡了功能需求和易用性,虽然能力不如AspectJ全面,但足以满足大多数企业应用的需求,且与Spring容器无缝集成。

© 版权声明
THE END
如果内容对您有所帮助,就支持一下吧!
点赞0 分享
vae半枫荷的头像 - 鹿快
评论 抢沙发

请登录后发表评论

    暂无评论内容