SpringAOP原理の分析

Springには主に2つのコアモジュールがあり、そのうちの1つはAOP(アスペクトプログラミング)です。通常、SpringAOPアノテーションバージョンを使用する場合、アスペクトクラスを定義し、エントリポイントを定義します。次に、定義されたエントリポイントは、@ Before-notification、@ After-notification処理、@ AfterReturning return通知処理、 @AfterThrowing例外通知処理、@ Aroundは通知処理を囲み、最後に@EnableAspectJAutoProxyアノテーションを構成クラス(または通常はSpringBootのスタートアップクラス)に追加して、SpringのAOP構成を構成します。

 @EnableAspectJAutoProxyアノテーションは何をしますか?

名前が示すように、この注釈はAOPアスペクトプログラミングを開くことを意味します。@ EnableXXXのような多くの注釈がSpringBootで使用されます。これらの注釈のほとんどは、特定の機能を有効にするために使用されます。実際、それらのほとんどは@Import注釈とともにパッケージ化されています。 。@Importアノテーションの機能は、コンポーネントをIOCコンテナにインポートすることです。コンポーネントをインポートする方法は3つあります。

  1. @Import(Car.Class)などのクラスオブジェクトの形式でインポートこれは、Carオブジェクトをコンテナにインポートするのと同じです。
  2. ImportSelectから継承されたクラスをカスタマイズし、内部のselectImportsメソッドをオーバーライドして、コンテナーにインポートする必要があるコンポーネントの完全なクラス名を返します。
  3. ImportBeanDefinitionRegistrarから継承されたクラスをカスタマイズし、内部のregisterBeanDefinitionsメソッドを書き直し、パラメーターBeanDefinitionRegistry.registerBeanDefinition( "book"、new RootBeanDefinition(Book.class))を使用してコンポーネントをコンテナーにインポートします。

 次に、@ EnableAspectJProxyアノテーションをクリックして確認します

案の定、@ Importアノテーションも内部で使用されているので、@ Importアノテーションのクラスを確認してください。

3番目の方法がコンポーネントのインポートに使用されていることがわかります。では、どのBeanがここにインポートされますか?registerAspectJAnnotationAutoProxyCreatorIfNecessaryメソッドについて詳しく見ていきましょう

したがって、インポートされたコンポーネントはAnnotationAwareAspectJAutoProxyCreatorクラスであり、そのIDはorg.springframework.aop.config.internalAutoProxyCreatorであることがわかります。

AnnotationAwareAspectJAutoProxyCreatorは何をしますか?

1.AnnotationAwareAspectJAutoProxyCreatorを登録します

まず、このクラスの役割を知る必要があります。まず、このクラスに移動してその継承構造を確認し、Springコンテナが初期化されるときに特別な処理が行われるように、このクラスがいくつかの特別なクラスを継承するかどうかを確認します。

このクラスに移動して、このクラスの継承レベルが高いことを確認します。このクラスの継承構造を以下に示します。

AnnotationAwareAspectJAutoProxyCreator-
> AspectJAwareAdvisorAutoProxyCreator-
  > AbstractAdvisorAutoProxyCreator-
    > AbstractAutoProxyCreator(継承有父クラス)
      はSmartInstantiationAwareBeanPostProcessorBeanFactoryAwareを実装します

親クラスAbstractAutoProxyCreatorにも2つのインターフェイスが実装されていることがわかります。それらは、Beanの初期化に関連するSmartInstantiationAwareBeanPostProcessorと、BeanFactoryの初期化に関連するBeanFactoryAwareです。次に、これら2つのインターフェイスのメソッドをAnnotationAwareAspectJAutoProxyCreatorとその親クラスで見つけて、ブレークポイントに到達します。AbstractAdvisorAutoProxyCreatorクラスがBeanFactoryAwareのsetBeanFactoryメソッドを書き換えてから、initBeanFactoryメソッドを呼び出すことがわかります。このメソッドもAnnotationAwareAspectJAutoProxyCreatorクラスによって上書きされるため、AbstractAdvisorAutoProxyCreatorのsetBeanFactoryにブレークポイントを設定します。 AbstractAutoProxyCreatorのpostProcessBeforeInstantiationメソッドが機能しなくなります。次に、デバッグして、メソッドがどのように呼び出されるかを確認できます。

プロジェクトを開始するとすぐに、プログラムがsetBeanFactoryメソッドに到達したことがわかりました。次に、左下隅にあるメソッド呼び出しスタックを調べて、setBeanFactoryメソッドに段階的に到達する方法を確認できます。

まず、最初にコンテナを初期化する必要があるので、refreshメソッドでコンテナを更新します。

refreshメソッドには、BeanPostProcessorを登録するために使用されるメソッドがあります。これは、実際にはBeanPostProcessorオブジェクトを作成し、それをコンテナーに格納するプロセスです。また、懸念しているAnnotationAwareAspectJAutoProxyCreatorクラスも間接的にBeanPostProcessorインターフェイスを実装しているため、内部の作業はAnnotationAwareAspectJAutoProxyCreatorと素晴らしい関係にあります。

次に、PostProcessorRegistrationDelegateのregisterBeanPostProcessorsメソッドに至るまで、このメソッドにブレークポイントを設定して、内部で実行されている作業を確認できます。

すべてのBeanPostProcessorの完全なクラス名を取得するための最初のステップに来てください

次のロジックはほぼ同じです。つまり、AnnotationAwareAspectJAutoProxyCreatorがOrderedインターフェイスを実装しているため、BeanPostProcessorインスタンスに優先度を決定させるため、Orderedの判定ブランチに移動し、OrderedBeanPostProcessorの完全なクラス名をOrderedに追加しました。 Listコレクションでは、以下はコレクションのトラバーサルの初期化に対応するBeanPostProcessorインスタンスであり、具体的にはAnnotationAwareAspectJAutoProxyCreatorを参照します。

次に、beanFactory.getBeanメソッドに深く入り込み、doCreateBean()メソッドに到達し、initializeBeanメソッドで実行しました。

この方法に飛び込む

これで中断した場所になります。次の初期化操作を確認して、initializeBeanメソッド全体を終了できます。

最後に、各BeanPostProcessorをBeanFactoryに追加します

この時点で、AnnotationAwareAspectJAutoProxyCreatorの登録プロセスはおそらく終了しています。AnnotationAwareAspectJAutoProxyCreatorの登録プロセスを要約してみましょう。

  1. @EnableAspectJAutoProxyアノテーション用にインポートする必要があるAnnotationAwareAspectJAutoProxyCreatorコンポーネントを含む、IOCコンテナで定義されているすべてのBeanPostProcessorsの完全なクラス名を取得します
  2. 別のBeanPostProcessorをコンテナに追加します
  3. PriorityOrderedインターフェースを最初に実装するBeanPostProcessorを登録します
  4. 次に、Orderedインターフェイスを実装するBeanPostProcessorを登録します
  5. 最後に通常のBeanPostProcessorを登録します
  6. getBeanメソッドを呼び出して、完全なクラス名に従ってBeanPostProcessorオブジェクトを登録(作成)し、コンテナーに保存します。これは、具体的にはAnnotationAwareAspectJAutoProxyCreator BeanPostProcessorの作成を指します。このプロセスでは、Beanインスタンスの作成、populateBean()-> Beanへのさまざまな属性の付与が含まれます。割り当て、Awareインターフェイスのコールバックの処理、postProcessBeforeInitialization()の適用、カスタムinitメソッドの実行、ポストプロセッサのpostProcessAfterInitialization()の適用
  7. 登録されたBeanPostProcessorをBeanFactory-> beanFactory.addBeanPostProcessor(postProcessor)に追加します

2.AnnotationAwareAspectJAutoProxyCreatorの役割

上記では、コンテナ内のAnnotationAwareAspectJAutoProxyCreatorの登録(作成)プロセスについて説明しましたが、このコンポーネントを作成するとどのような影響がありますか?実際、このクラスは間接的にInstantiationAwareBeanPostProcessorインターフェイスの実装クラスであり、このインターフェイスはBeanPostProcessorインターフェイスを継承していることがわかります。

したがって、作成したAnnotationAwareAspectJAutoProxyCreatorはInstantiationAwareBeanPostProcessorのBeanPostProcessorであり、このインターフェイスを実装するBeanPostProcessorの特別な役割は何ですか?実際、Spring refreshメソッドがコンテナを初期化するとき、1つのステップは残りのBeanメソッドを初期化することです。このメソッドは実際に通常のカスタムクラスを初期化することです。これらのクラスを初期化するときなので、以下でこのメソッドを見てみましょう。 、InstantiationAwareBeanPostProcessorインターフェイスを実装するBeanPostProcessorがその中で機能します。

AbstractAutoProxyCreatorのInstantiationAwareBeanPostProcessorインターフェイスのpostProcessBeforeInstantiationメソッドを書き直し、ブレークポイントを設定して、このプロセスがどのメソッドを通過したかを確認します。

最初に来るのは、refreshメソッドのfinishBeanFactoryInitializationメソッドです。

 getBeanメソッドまで移動します

先に進んで、次の方法に来てください

resolveBeforeInstantiationメソッドによって返されるBeanがnullでない場合は直接戻り、作成は成功します。それ以外の場合は、doCreateBeanメソッドを使用してBeanを作成します。

resolveBeforeInstantiationメソッドについて詳しく見ていきましょう

詳細なapplyBeanPostProcessorsBeforeInstantiationメソッド

これがInstantiationAwareBeanPostProcessorインターフェイスの役割であることがわかります。Beanインスタンスを作成する前に、最初にすべてのBeanPostProcessorを取得します。トラバースしたBeanPostProcessorがInstantiationAwareBeanPostProcessorインターフェイスを実装している場合は、このBeanPostProcessorを使用して、書き換えられたpostProcessBeforeInstantiationメソッドを呼び出します。 Beanインスタンスを返すことができる場合は返し、戻り値がnullの場合は直接返し、doCreateBean(このプロセスは上記のBeanPostProcessorを作成するプロセスと一致します)を使用してBeanインスタンスを作成します。したがって、ここでは、BeanPostProcessorインターフェイスを直接実装するコンポーネントが、すべてのBeanインスタンスが作成される前後で機能し、InstantiationAwareBeanPostProcessorインターフェイスを実装するコンポーネントが、すべてのBeanインスタンスが作成される前にインターセプトされること、つまりBeanを返そうとすることもわかります。インスタンス。つまり、AnnotationAwareAspectJAutoProxyCreatorは、他のすべてのBeanインスタンスが作成される前に、プロキシオブジェクトを返そうとします。

3.AOPプロキシオブジェクトを作成します

AbstractAutoProxyCreator(AnnotationAwareAspectJAutoProxyCreatorの親クラス)のpostProcessBeforeInstantiationメソッドを使用して、Beanインスタンスを作成する前にインスタンスを取得しようとするので、ここでこのメソッドを見てみましょう。

ここではAOPオブジェクトの作成を確認しているので、これらのAOPオブジェクトの作成にブレークポイントを設定します。まず、デモのAOPクラスについて説明します。

プロキシされるオブジェクト:

強化方法:

構成クラス:

さて、上記はAOPクラスに関するものです。引き続き、AbstractAutoProxyCreatorのpostProcessBeforeInstantiationメソッドを確認します。

最初に、初期化する必要のあるBeanがadviceBeansにあるかどうかを判別し、次に、BeanがAdvice、PointCut、Advisor、AopInfrastructureBean、またはAspectの基本タイプであるかどうかを判別します。初期化するクラスが拡張が必要な​​Calculateである場合、次のようになります。このクラスは上記のタイプの1つではないため、False。

AnnotationAwareAspectJAutoProxyCreatorによって書き直されたshouldSkipメソッドもあります

親クラスAbstractAutoProxyCreatorのshouldSkipメソッドはfalseを直接返します

したがって、要約すると、ここでのshouldSkip呼び出しの結果は常にfalseを返すはずです。

次に、次の判断を見てください

nullが返されるため、コンテナはこのBeanを作成する必要があります。このBeanを作成した後、BeanPostProcessor(AbstractAutoProxyCreator)のpostProcessAfterInitializationメソッドを通過します。

その中の主なロジックはwrapIfNecessaryメソッドにあります。このメソッドは主にプロキシオブジェクトを作成するためのものなので、それがどのように作成されるかを見てみましょう。

次に、以下を見てください

これは、現在作成されているBeanに適用できるすべてのエンハンサーを見つけるためのものです。詳しく見てください。

 上記では、適用可能なすべてのエンハンサーを取得してから、

重要なのはcreateProxyメソッドです。名前から、これがプロキシオブジェクトを作成するためのメソッドであることがわかります。詳しく見てみましょう。

プロキシオブジェクトを返すメソッドを深く掘り下げて、createAopProxyメソッドに移動します。

最終的に、取得するのは、cglibまたはjdkによって作成された動的プロキシオブジェクトです。プロセスの要約は、AOPプロキシを作成するプロセスで、Beanを初期化した後(postProcessAfterInitializationメソッド)、Beanに従って対応する拡張メソッドを見つけ、対応する拡張メソッドがある場合は、オブジェクトの動的プロキシを作成するということです。オブジェクト、オブジェクトがない場合は、オブジェクトを直接返すため、後でコンテナに入るのは、このコンポーネントのプロキシオブジェクトです。

4.インターセプターチェーンMethodInterceptorを取得します

まず、ターゲットを拡張する必要があるメソッドにブレークポイントデバッグを設定しましょう。

この時点でインターセプトメソッドが到着していることがわかります。名前を聞くと、このメソッドがターゲットメソッドの実行をインターセプトすることであることがわかります。焦点は以下のインターセプターチェーンを作成するロジックにあります。

次に、主にインターセプターチェーンの作成方法を確認し、インターセプターチェーンの作成方法を入力します。

これはキャッシングに関するいくつかのロジックです。インターセプターチェーンの主な作成はメソッドgetInterceptorsAndDynamicInterceptionAdviceであり、メソッドを入力します

まず、メインロジックがこのforループにあり、アドバイザのコレクションがトラバースされていることがわかります。このコレクションには、デフォルトのExposeInvocationInterceptorと4つのエンハンサーがあります。そして、おそらくすべてのアドバイザーをインターセプターに変換することです

MethodInterceptorタイプの場合はコレクションに追加し、そうでない場合は、対応するAdvisorAdapterを使用してMethodInterceptorに変換し、コレクションに追加します。したがって、各アドバイザをトラバースすると、各アドバイザは対応するインターセプタチェーン配列を取得し、その配列をインターセプタコンテナに配置します。

5.チェーンコール通知方法

上記のインターセプターチェーンを取得しました。このインターセプターチェーンで通知メソッドを呼び出す方法は?上記のことから、取得したインターセプターチェーンが空でない場合、つまり、ターゲットメソッドに作用する拡張メソッドがある場合、拡張メソッドを実行するためにproceedを呼び出すために新しいCglibMethodInvocationが必要であることがわかります。このproceedメソッドがどのように実行されるかを見てみましょう

まず、上記は、現在のインターセプターチェーンが空であるか、現在来るインターセプターの座標インデックスがインターセプターチェーンの最後の座標インデックスと等しいかを最初に判断し、次にターゲットメソッドを直接実行してから、currentInterceptorIndexに従ってインターセプターチェーンを取得します。対応するインターセプター(初めてExposeInvocationInterceptorを取得しました)。次に、次のキー((MethodInterceptor)interceptorOrInterceptionAdvice).invoke(this)このコード行を確認し、現在のReflectiveMethodInvocationオブジェクトがここに渡されていることに注意してください。次に、入力して確認します。

ここでは、渡されたReflectiveMethodInvocationオブジェクトを使用してproceedメソッドを再度呼び出します。つまり、この時点で、proceedメソッドに戻り、インターセプターチェーンから2番目のインターセプターを取得するため、これは1つのレイヤー1に相当します。次のインターセプターのinvokeメソッドをレイヤーごとに呼び出すために、最後のインターセプターMethodBeforeAdviceInterceptorを直接調べます。

 proceedメソッドが実行される前にbeforeメソッドがあることがわかります。実際、このメソッドは事前通知を実行するために使用され、事前通知が実行された後にproceedを実行します。

この時点で、proceedメソッドの開始時の判断条件により、現在のインターセプターがインターセプターチェーンの最後のインターセプターであると判断でき、ターゲットメソッドが直接実行されるため、ログが事前通知の結果を満たしていることがわかります。

 次に、インターセプターのinvokeメソッドはレイヤーごとに呼び出されるため、最後のインターセプターがinvokeメソッドを実行すると、最後から2番目のインターセプターのinvokeメソッドに戻り続けます。ここで画像を渡すことができます。 invokeメソッドの呼び出しフローを描画するには

 6.AOPプロセスの概要

まず、最初の@EnableAspectJAutoProxyアノテーションがAOP関数を有効にします。目的はAnnotationAwareAspectJAutoProxyCreatorコンポーネントをコンテナにインポートすることであり、このコンポーネントはBeanPostProcessorです。Springコンテナの初期化中に、SpringのrefreshメソッドにregisterBeanPostProcessorsメソッドがあります。このメソッドはすべてのBeanPostProcessorsを作成して、AnnotationAwareAspectJAutoProxyCreatorコンポーネントをここで作成してから、finishBeanFactoryInitializationメソッドにアクセスして、残りの単一インスタンスBeanを作成します。この時点で、アスペクトコンポーネントを含む、プログラム内のビジネスロジックコンポーネントが作成され、これらのコンポーネントが作成される前後に、コンテナに作成されたBeanPostProcessorがインターセプトされて処理されます。その中で、AnnotationAwareAspectJAutoProxyCreatorコンポーネントはBeanを作成する前にBeanを返そうとします。戻れない場合は、正常に実行されてBeanが作成されます。Beanの作成後、AnnotationAwareAspectJAutoProxyCreatorはpostProcessAfterInitializationメソッド(Beanの作成後に呼び出されます)を使用して、Beanがプロキシオブジェクトを作成する必要があるかどうかを判断します。ここでは、クラスがインターフェイスを実装するかどうかに応じて、JDK動的プロキシまたはcglib動的プロキシを使用できます。拡張する必要がある場合、つまりプロキシオブジェクトを作成する必要がある場合は、ポイントカットとポイントカットのすべての通知メソッドをアドバイザエンハンサーにラップしてから、プロキシオブジェクトを作成します。ターゲットメソッドを実行するときは、最初にターゲットメソッドのインターセプターチェーンを取得し、インターセプターのチェーン呼び出しメカニズムを使用して、一度に各インターセプターに入り、拡張メソッドを実行します。

 

おすすめ

転載: blog.csdn.net/weixin_37689658/article/details/101173206