Xuewei HUANG

Xuewei's Blog

工欲善其事,必先利其器.
github

Spring AOP 原理分析

TL;DR#

image_1723722735889_0 image_1723722759799_0 Spring AOP 拦截器链执行
  • @EnableAspectJAutoProxy 开启自动代理
    • Context 启动会创建 AnnotationAwareAspectJAutoProxyCreator 的 BeanDefinition 放到「BeanFactory」中的「beanDefinitionMap」
    • 创建的 bean 实例放到「BeanFactory」中的「singletonObjects」和「beanPostProcessors」
  • 前置处理,扫描所有 Aspect,生成所有的 Advisor,放入缓存
    • 在创建 Bean 流程中的「实例化 Bean 的前置处理阶段」,扫描所有 @Aspect 修饰的类,生成「Advisor (Advice + Pointcut)」列表,并缓存 advisorsCahce 中
  • 创建 Proxy Bean (JDK Proxy 或 cglib 实现)
    • 一般情况,在创建 Bean 流程中的「初始化 bean 的后置处理阶段」,但是在「循环依赖」情况下,会提前 AOP,在「填充 bean 属性阶段」,提前创建 Proxy Bean
    • 检查 Advisor 的 Pointcut 条件是否与 bean 对应类中任一方法「匹配」,存在匹配情况,若匹配放入 「eligibleAdvisors」 列表
    • 若「eligibleAdvisors」列表不为空,说明需要 AOP,进而创建 Proxy Bean,放入「BeanFactory」
      • ProxyBean -> AopProxy (JDK or Cglib) -> ProxyFacotry (advised) -> eligibleAdvisors
  • Proxy Bean 调用代理方法,调用「拦截器链」链式执行「Advice」的方法
    • 获取「Target Bean」和被调用方法所匹配的「拦截器链 (Advisor <-> MethodInterceptor)」
    • 通过创建 ReflectiveMethodInvocation 实例,递归调用 proceed 方法,遍历「拦截器链」,进行反射调用「拦截器」的 Advice 方法
    • ReflectiveMethodInvocation 实例通过维护 currentInterceptorIndex 索引来遍历「拦截器链」,当遍历完「拦截器链」会调用 invokeJoinpoint 方法,调用「Target Bean」的目标方法。

什么是 AOP?#

  • AOP (Aspect Oriented Programming, 面向切面编程) 是一种「编程范式」
  • 本质是将「核心功能」与「切面功能」进行「解耦」,可分别独立进行开发功,然后将「核心功能」和「切面功能」进行「织入 Weaving」

什么是 Spring AOP?#

  • 结合 Spring IOC 容器,通过在创建 Bean 过程中进行增强,生成 Proxy Bean,实现在程序 Runtime 期间,「动态」地将「核心功能」和「切面功能」进行「织入 Weaving」
  • 本质就是,通过「代理模式 (动态代理)」实现 AOP,并结合 Spring IOC 容器,存放 Proxy Bean

相关概念#

  • Jointpoint: 连接点 (方法执行,异常处理)
  • Pointcut: 切点
  • Advice: 在 Jointpoint 执行的「切面功能」操作

    也叫「通知」,包括 Around, Before, After, AfterReturning, AfterThrowing

  • Advisor: Pointcut + Advice

Spring AOP 的工作流程#

  1. 开启 AspectJ 注解自动代理

    生成 AnnotationAwareAspectJAutoProxyCreator 的 bean 实例,放入「BeanFactory」中的「beanDefinitionMap」,「singletonObjects」和「beanPostProcessors」

    Spring_AOP_注解自动代理_1723188520212_0

    • Spring AOP 开启 AspectJ 自动代理对应的注解是 @EnableAspectJAutoProxy,通过注解 @Import 导入 AspectJAutoProxyRegistrar
    • AspectJAutoProxyRegistrar 作用是将 AnnotationAwareAspectJAutoProxyCreator 生成对应的 BeanDefinition 对象,放入到 BeanDefinition 注册中心中
    • AnnotationAwareAspectJAutoProxyCreator
      • 根据 BeanDefinition 创建 AnnotationAwareAspectJAutoProxyCreator 的 Bean 对象,并加入到 BeanFactory 的 beanPostProcessors (Bean 处理器列表) 中
      • 实现了 SmartInstantiationAwareBeanPostProcessor 接口,重要的方法如下
        1. Bean 初始化前置处理方法: postProcessBeforeInitialization()
        2. 获取早期 Bean 引用: getEarlyBeanReference()
        3. Bean 初始化后置处理方法: postProcessAfterInitialization()
  2. 前置准备

    查找所有「切面 Aspect」类来生成「Advisor (Advice + Pointcut)」列表,并缓存起来

    Spring_AOP_前置处理_1723304931489_0

    • 在创建 Bean 的流程,在「实例化 Bean」之前的阶段 「resolveBeforeInstantiation」
    • 在第一次调用 AnnotationAwareAspectJAutoProxyCreator 的 bean 实例的postProcessBeforeInstantiation 方法
      • 从「BeanFacotry」中获取所有的 Bean Name,遍历 Bean Name 列表,根据 beanName 查询「beanDefinitonMap」对应的类,是否含有 @Aspect 注解
      • 对含有 @Aspect 的类,扫描其所有的「Advice」方法和对应的「Pointcut」方法,生成「Advisor」列表
      • 将「Advisor」列表缓存到 advisorCache Map 中
  3. 创建 Proxy Bean

    若在创建 Bean 过程,与「Advisor」集合任意匹配成功,创建 AOP 代理对象

    Spring_AOP_在初始化_bean_后置处理创建_Proxy_Bean_1723722535436_0
    • 一般情况下,进行 AOP 创建 Proxy Bean,是在「初始化 bean 后置处理阶段」

      • 在创建 bean 流程的「初始化 bean 后置处理阶段」
      • 调用 AnnotationAwareAspectJAutoProxyCreator 的 bean 实例的 postProcessAfterInitialization 方法,调用 wrapIfNecessary 方法创建 Proxy Bean
      • 从「advisorsCache」获取所有的 Advisor,通过查看当前需要创建的 bean 的类中,是否有任一方法与「Advisor 的 Pointcut 条件」匹配,从而筛选出匹配的「eligibleAdvisors」列表
      • 创建 ProxyFactory 实例
        • 将「匹配 advisor 列表」设置到 ProxyFactory 的「advisors」属性中
        • 将包装了「实例化的 bean」的 SingletonTargetSource 实例设置到 ProxyFactory 的「targetSource」属性中
      • 调用 ProxyFactory 实例的 createAopProxy 方法,根据条件选择创建 AopProxy 实例
        • 「JdkDynamicAopProxy」
        • 「ObjenesisCglibAopProxy」
      • 调用 Aop Proxy 实例的 getProxy 方法的实现 (JDK 或 Cglib),创建「Proxy Bean」
      • 将 Proxy Bean 放入到「BeanFactory 容器」的「singletonObjects」中
    • 在有「循环依赖」下,需提前进行 AOP,提前创建 Proxy Bean,是在「填充 bean 属性阶段」
      e96d64ab-3463-4e7a-839b-e1b91b276400

      Mermaid Loading...
      • 在创建 bean 流程的「填充 bean 属性阶段」
      • 调用 AnnotationAwareAspectJAutoProxyCreator 的 bean 实例的 getEarlyBeanReference 方法,进行提前 AOP,调用 wrapIfNecessary 方法创建 Proxy Bean
      • 创建 Proxy Bean 与一般情况一样,详情看上述一般情况
  4. Proxy Bean 调用代理方法,调用「拦截器链」链式执行「Advice」方法
    Spring AOP 拦截器链执行

    • 调用 Proxy Bean 实例的方法,调用代理方法
      • JDK 代理,调用的是 JdkDynamicAopProxy (InvocationHandler) 的 invoke 方法
      • Cglib 代理,调用的是 ObjenesisCglibAopProxy 的 intercept 方法
    • 从 advised (即 ProxyFactory) 中取出「原始 Bean (Target Bean)」
    • 构建与「被调用方法 callee method」所匹配的「拦截器链」
      • 从 advised (即 ProxyFactory) 中的与 bean 的类所匹配的所有的 「Advisor」
      • 然后遍历检查「Advisor」是否与当前方法匹配
      • 与当前方法匹配的「Advisor」,进行构建出对应的「Interceptor 拦截器」,放入「拦截器链」列表中
      • 缓存和返回「拦截器链」
    • 构建 MethodInvocation,包装 Proxy Bean, Target Bean, 「拦截器链」等,执行「拦截器链」
      • 根据不同代理创建不同的  MethodInvocation,递归调用 proceed 方法
        • JDK 代理,创建 ReflectiveMethodInvocation,进行递归调用 ReflectiveMethodInvocation 的 proceed 方法
        • Cglib 代理,创建 CglibMethodInvocation,进行递归调用 ReflectiveMethodInvocatio 的 proceed 方法 (CglibMethodInvocation 继承了 ReflectiveMethodInvocatio)
      • 通过反射调用「拦截器」的 Advice 方法
      • ReflectiveMethodInvocation 实例通过维护 currentInterceptorIndex 索引来遍历「拦截器链」
      • 如果已执行完「拦截器链」,调用 ReflectiveMethodInvocatio 的 invokeJoinpoint 方法,反射调用「原始 Bean (Target Bean)」的方法 (被代理)

拦截器与 Advice 和注解的关系#

  • @Around
    • Advice 和拦截器: AspectJAroundAdvice
  • @Before
    • 适配器: MethodBeforeAdviceAdapter
    • Advice: AspectJMethodBeforeAdvice->MethodBeforeAdvice
    • 拦截器: MethodBeforeAdviceInterceptor
  • @After
    • Advice 和拦截器: AspectJAfterAdvice
  • @AfterReturning
    • 适配器: MethodBeforeAdviceAdapter
    • Advice: AspectJAfterReturningAdvice->AfterReturningAdvice
    • 拦截器: AfterReturningAdviceInterceptor
  • @AfterThrowing
    • Advice 和拦截器: AspectJAfterThrowingAdvice
  • ThrowsAdviceAdapter 适配器,没有对应的注解
    • Advice: ThrowsAdvice
    • 拦截器: ThrowsAdviceInterceptor

「拦截器链」执行过程的时序图#

Mermaid Loading...

Refs:#

Loading...
Ownership of this post data is guaranteed by blockchain and smart contracts to the creator alone.