TL;DR#
- @EnableAspectJAutoProxy 自動プロキシを有効にする
- コンテキストの起動時に、AnnotationAwareAspectJAutoProxyCreator の BeanDefinition が「BeanFactory」の「beanDefinitionMap」に作成される
- 作成された bean インスタンスは「BeanFactory」の「singletonObjects」と「beanPostProcessors」に格納される
- 前処理、すべての Aspect をスキャンし、すべての Advisor を生成し、キャッシュに格納する
- Bean のインスタンス化プロセスの「前処理段階」で、すべての
@Aspect
で修飾されたクラスをスキャンし、「Advisor (Advice + Pointcut)」リストを生成し、advisorsCache にキャッシュする
- Bean のインスタンス化プロセスの「前処理段階」で、すべての
- 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」のターゲットメソッドを呼び出す。
- 「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 の作業フロー#
-
AspectJ アノテーション自動プロキシを有効にする
AnnotationAwareAspectJAutoProxyCreator の bean インスタンスを生成し、「BeanFactory」の「beanDefinitionMap」、「singletonObjects」と「beanPostProcessors」に格納する
- Spring AOP で AspectJ 自動プロキシを有効にするためのアノテーションは
@EnableAspectJAutoProxy
であり、アノテーション@Import
を通じて AspectJAutoProxyRegistrar をインポートする - AspectJAutoProxyRegistrar の役割は、AnnotationAwareAspectJAutoProxyCreator が生成する対応する BeanDefinition オブジェクトを BeanDefinition 登録センターに格納することである
- AnnotationAwareAspectJAutoProxyCreator
- BeanDefinition に基づいて AnnotationAwareAspectJAutoProxyCreator の Bean オブジェクトを作成し、BeanFactory の beanPostProcessors (Bean 処理器リスト) に追加する
- SmartInstantiationAwareBeanPostProcessor インターフェースを実装し、重要なメソッドは以下の通りである
- Bean 初期化前処理メソッド: postProcessBeforeInitialization()
- 早期 Bean 参照の取得: getEarlyBeanReference()
- Bean 初期化後処理メソッド: postProcessAfterInitialization()
- Spring AOP で AspectJ 自動プロキシを有効にするためのアノテーションは
-
前準備
すべての「アスペクト Aspect」クラスを探して「Advisor (Advice + Pointcut)」リストを生成し、キャッシュする
- Bean の作成プロセスにおいて、「Bean のインスタンス化」前の段階「resolveBeforeInstantiation」
- AnnotationAwareAspectJAutoProxyCreator の bean インスタンスのpostProcessBeforeInstantiationメソッドが初めて呼び出される
- 「BeanFactory」からすべての Bean 名を取得し、Bean 名リストを遍歴し、beanName に基づいて「beanDefinitionMap」に対応するクラスが
@Aspect
アノテーションを含んでいるかどうかを確認する @Aspect
を含むクラスに対して、そのすべての「Advice」メソッドと対応する「Pointcut」メソッドをスキャンし、「Advisor」リストを生成する- 「Advisor」リストを
advisorCache
Map にキャッシュする
- 「BeanFactory」からすべての Bean 名を取得し、Bean 名リストを遍歴し、beanName に基づいて「beanDefinitionMap」に対応するクラスが
-
Proxy Bean の作成
Bean の作成プロセスで「Advisor」集合と任意に一致した場合、AOP 代理オブジェクトを作成する
-
一般的には、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 属性の充填段階」である
Mermaid Loading...- Bean 作成プロセスの「bean 属性の充填段階」で
- AnnotationAwareAspectJAutoProxyCreator の bean インスタンスの getEarlyBeanReference メソッドを呼び出し、事前に AOP を行い、wrapIfNecessary メソッドを呼び出して Proxy Bean を作成する
- Proxy Bean の作成は一般的な場合と同様であり、詳細は上記の一般的な場合を参照
-
-
Proxy Bean が代理メソッドを呼び出し、「インターセプターのチェーン」を連鎖的に実行する「Advice」メソッドを呼び出す
- 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)」のメソッドを呼び出す(代理された)
- 異なる代理に基づいて異なる MethodInvocation を作成し、proceed メソッドを再帰的に呼び出す
- Proxy 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...