Xuewei HUANG

Xuewei's Blog

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

Spring AOPの原理分析

TL;DR#

image_1723722735889_0 image_1723722759799_0 Spring AOP 拦截器链执行
  • @EnableAspectJAutoProxy 自動プロキシを有効にする
    • コンテキストの起動時に、AnnotationAwareAspectJAutoProxyCreator の BeanDefinition が「BeanFactory」の「beanDefinitionMap」に作成される
    • 作成された bean インスタンスは「BeanFactory」の「singletonObjects」と「beanPostProcessors」に格納される
  • 前処理、すべての Aspect をスキャンし、すべての Advisor を生成し、キャッシュに格納する
    • Bean のインスタンス化プロセスの「前処理段階」で、すべての@Aspectで修飾されたクラスをスキャンし、「Advisor (Advice + Pointcut)」リストを生成し、advisorsCache にキャッシュする
  • Proxy Bean の作成 (JDK Proxy または cglib 実装)
    • 一般的には、Bean の初期化後処理段階で Proxy Bean を作成するが、「循環依存」の場合は AOP を事前に行い、「bean 属性の充填段階」で Proxy Bean を事前に作成する
    • Advisor の Pointcut 条件が bean 対応クラスの任意のメソッドと「一致」するかどうかを確認し、一致する場合は「eligibleAdvisors」リストに追加する
    • 「eligibleAdvisors」リストが空でない場合、AOP が必要であることを示し、Proxy Bean を作成し、「BeanFactory」に格納する
      • ProxyBean -> AopProxy (JDKまたはCglib) -> ProxyFactory (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 を生成し、プログラムのランタイム中に「動的」に「コア機能」と「アスペクト機能」を「織り込む 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メソッドが初めて呼び出される
      • 「BeanFactory」からすべての Bean 名を取得し、Bean 名リストを遍歴し、beanName に基づいて「beanDefinitionMap」に対応するクラスが@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 を作成し、ReflectiveMethodInvocation の proceed メソッドを再帰的に呼び出す(CglibMethodInvocation は ReflectiveMethodInvocation を継承している)
      • 「インターセプター」の Advice メソッドを反射的に呼び出す
      • ReflectiveMethodInvocation インスタンスは currentInterceptorIndex インデックスを維持して「インターセプターのチェーン」を遍歴する
      • 「インターセプターのチェーン」を実行し終えたら、ReflectiveMethodInvocation の 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:#

読み込み中...
文章は、創作者によって署名され、ブロックチェーンに安全に保存されています。