Spring AOP实现原理

AOP核心概念

核心概念解析

  • Aspect(切面): 封装横切关注点的模块,包含多个 AdvicePointcut,如日志切面、事务切面、权限校验切面。
  • 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 的关系

维度Spring AOPAspectJ
织入时机 运行时动态代理 编译时或类加载时(支持更丰富的连接点)
性能 略低(运行时生成代理) 更高(编译时优化)
功能范围 仅支持方法级别的连接点 支持字段、构造器、静态代码块等连接点
使用场景 轻量级应用,无需复杂切面 企业级复杂切面需求(如性能监控、安全检查)

JDK动态代理与CGLIB代理的底层实现

JDK 动态代理

  • 核心原理

    • 基于接口:要求目标对象必须实现至少一个接口。

    • 反射机制:通过 java.lang.reflect.ProxyInvocationHandler 动态生成代理类。

    • 代理对象行为:代理类实现目标接口,并将方法调用转发到 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 代理对比

维度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)等。
    • 继承关系ProxyFactoryProxyCreatorSupportAdvisedSupport
  • 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

注解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递归调用拦截器,直至执行目标方法。
#Spring##java#
全部评论

相关推荐

评论
1
收藏
分享

创作者周榜

更多
牛客网
牛客企业服务