1. 序章

現在、利用可能なAOPライブラリは複数あり、これらはいくつかの質問に答えられる必要があります。

  • 既存または新規のアプリケーションと互換性がありますか?
  • AOPはどこに実装できますか?
  • どのくらい早く私のアプリケーションと統合されますか?
  • パフォーマンスのオーバーヘッドはどれくらいですか?

この記事では、これらの質問への回答を見て、Javaで最も人気のある2つのAOPフレームワークであるSpringAOPとAspectJを紹介します。

2. AOPの概念

始める前に、用語とコアコンセプトの簡単で高レベルのレビューを行いましょう。

  • アスペクト–アプリケーション内の複数の場所に散在し、通常は実際のビジネスロジック(トランザクション管理など)とは異なる標準のコード/機能。 各側面は、特定の分野横断的な機能に焦点を当てています
  • ジョインポイント–メソッドの実行、コンストラクターの呼び出し、フィールドの割り当てなどのプログラムの実行中の特定のポイントです。
  • アドバイス–特定のジョインポイントのアスペクトによって実行されるアクション
  • ポイントカット–ジョインポイントに一致する正規表現。 参加ポイントがポイントカットと一致するたびに、そのポイントカットに関連付けられた指定されたアドバイスが実行されます
  • ウィービング–アスペクトをターゲットオブジェクトとリンクして、アドバイスされたオブジェクトを作成するプロセス

3. 春のAOPとAspectJ

それでは、機能、目標、織り方、内部構造、結合点、単純さなど、さまざまな軸にわたってSpringAOPとAspectJについて説明しましょう。

3.1. 機能と目標

簡単に言えば、SpringAOPとAspectJの目標は異なります。

Spring AOPは、プログラマーが直面する最も一般的な問題を解決するために、SpringIoC全体に単純なAOP実装を提供することを目的としています。 完全なAOPソリューションとして意図されたものではありません–Springコンテナによって管理されるBeanにのみ適用できます。

一方、 AspectJは、完全なAOPソリューションを提供することを目的とした独自のAOPテクノロジーです。これは、Spring AOPよりも堅牢ですが、大幅に複雑です。 AspectJはすべてのドメインオブジェクトに適用できることにも注意してください。

3.2. 織り

AspectJとSpringAOPはどちらも、パフォーマンスと使いやすさに関する動作に影響を与える異なるタイプの織りを使用しています。

AspectJは、次の3種類の織りを利用しています。

  1. コンパイル時ウィービング:AspectJコンパイラーは、アスペクトのソースコードとアプリケーションの両方を入力として受け取り、ウィーブされたクラスファイルを出力として生成します。
  2. コンパイル後の織り:これはバイナリ織りとも呼ばれます。 これは、既存のクラスファイルとJARファイルを私たちの側面で織り込むために使用されます
  3. ロード時のウィービング:これは以前のバイナリウィービングとまったく同じですが、クラスローダーがクラスファイルをJVMにロードするまでウィービングが延期される点が異なります。

AspectJ自体の詳細については、この記事に進んでください。

AspectJはコンパイル時とクラスロード時ウィービングを使用するため、SpringAOPはランタイムウィービングを利用します。

ランタイムウィービングでは、JDK動的プロキシまたはCGLIBプロキシ(次のポイントで説明)のいずれかを使用して、ターゲットオブジェクトのプロキシを使用してアプリケーションの実行中にアスペクトがウィービングされます。

3.3. 内部構造とアプリケーション

Spring AOPは、プロキシベースのAOPフレームワークです。 これは、ターゲットオブジェクトにアスペクトを実装するために、そのオブジェクトのプロキシを作成することを意味します。 これは、次の2つの方法のいずれかを使用して実現されます。

  1. JDK動的プロキシ–SpringAOPに推奨される方法。 ターゲットオブジェクトが1つのインターフェイスを実装する場合は常に、JDK動的プロキシが使用されます
  2. CGLIBプロキシ–ターゲットオブジェクトがインターフェイスを実装していない場合は、CGLIBプロキシを使用できます

Spring AOPプロキシメカニズムの詳細については、公式ドキュメントをご覧ください。

一方、AspectJは、クラスがアスペクトを使用して直接コンパイルされるため、実行時に何も実行しません。

そのため、Spring AOPとは異なり、デザインパターンは必要ありません。 コードにアスペクトを織り込むために、AspectJコンパイラ(ajc)と呼ばれるコンパイラを導入します。これにより、プログラムをコンパイルし、小さな(<100K)ランタイムライブラリを提供して実行します。

3.4. 参加ポイント

セクション3.3では、SpringAOPがプロキシパターンに基づいていることを示しました。 このため、対象のJavaクラスをサブクラス化し、それに応じて横断的関心事を適用する必要があります。

ただし、制限があります。 「最終」であるクラスに横断的関心事(またはアスペクト)を適用することはできません。これは、それらをオーバーライドできないため、実行時の例外が発生するためです。

同じことが静的メソッドとfinalメソッドにも当てはまります。 スプリングアスペクトはオーバーライドできないため、適用できません。 したがって、Spring AOPはこれらの制限のため、メソッド実行の結合点のみをサポートします。

ただし、 AspectJは、実行前に横断的関心事を実際のコードに直接織り込みます。 Spring AOPとは異なり、ターゲットオブジェクトをサブクラス化する必要がないため、他の多くの結合点もサポートします。 サポートされている参加ポイントの概要は次のとおりです。

ジョインポイント SpringAOPがサポートされています AspectJがサポートされています
メソッド呼び出し いいえ はい
メソッドの実行 はい はい
コンストラクター呼び出し いいえ はい
コンストラクターの実行 いいえ はい
静的初期化子の実行 いいえ はい
オブジェクトの初期化 いいえ はい
フィールドリファレンス いいえ はい
フィールド割り当て いいえ はい
ハンドラーの実行 いいえ はい
アドバイスの実行 いいえ はい

また、Spring AOPでは、同じクラス内で呼び出されるメソッドにアスペクトが適用されないことにも注意してください。

これは明らかに、同じクラス内のメソッドを呼び出すときに、SpringAOPが提供するプロキシのメソッドを呼び出さないためです。 この機能が必要な場合は、別のBeanで別のメソッドを定義するか、AspectJを使用する必要があります。

3.5. シンプルさ

Spring AOPは、ビルドプロセスの間に余分なコンパイラやウィーバーを導入しないため、明らかに単純です。 ランタイムウィービングを使用するため、通常のビルドプロセスとシームレスに統合されます。 見た目はシンプルですが、Springによって管理されているBeanでのみ機能します。

ただし、AspectJを使用するには、AspectJコンパイラー(ajc)を導入し、すべてのライブラリーを再パッケージ化する必要があります(コンパイル後またはロード時のウィービングに切り替えた場合を除く)。

もちろん、これは前者よりも複雑です。これは、AspectJ Javaツール(コンパイラー(ajc)、デバッガー(ajdb)、ドキュメントジェネレーター(ajdoc)、プログラム構造ブラウザー(ajbrowser)を含む)を導入しているためです。 IDEまたはビルドツールのいずれかと統合する必要があります。

3.6. パフォーマンス

パフォーマンスに関する限り、コンパイル時のウィービングはランタイムウィービングよりもはるかに高速です。 Spring AOPはプロキシベースのフレームワークであるため、アプリケーションの起動時にプロキシが作成されます。 また、アスペクトごとにさらにいくつかのメソッド呼び出しがあり、パフォーマンスに悪影響を及ぼします。

一方、AspectJは、アプリケーションが実行される前にアスペクトをメインコードに織り込むため、Spring AOPとは異なり、追加のランタイムオーバーヘッドはありません。

これらの理由から、ベンチマークは、AspectJがSpring AOPよりも約8〜35倍高速であることを示しています。

4. 概要

このクイックテーブルは、SpringAOPとAspectJの主な違いをまとめたものです。

春のAOP AspectJ
純粋なJavaで実装 Javaプログラミング言語の拡張機能を使用して実装
個別のコンパイルプロセスは必要ありません LTWが設定されていない限り、AspectJコンパイラ(ajc)が必要です
ランタイムウィービングのみが利用可能です ランタイムウィービングは利用できません。 コンパイル時、コンパイル後、およびロード時のウィービングをサポートします
あまり強力ではない–メソッドレベルのウィービングのみをサポート より強力–フィールド、メソッド、コンストラクター、静的初期化子、最終クラス/メソッドなどを織り込むことができます…
Springコンテナによって管理されるBeanにのみ実装できます すべてのドメインオブジェクトに実装できます
メソッド実行ポイントカットのみをサポート すべてのポイントカットをサポートする
プロキシはターゲットオブジェクトで作成され、アスペクトはこれらのプロキシに適用されます アプリケーションが実行される前(実行前)に、アスペクトがコードに直接織り込まれます
AspectJよりもはるかに遅い よりよい性能
習得と適用が簡単 SpringAOPよりも比較的複雑

5. 適切なフレームワークの選択

このセクションで行われたすべての議論を分析すると、あるフレームワークが別のフレームワークよりも優れているわけではないことが理解できるようになります。

簡単に言えば、選択は私たちの要件に大きく依存します:

  • フレームワーク:アプリケーションがSpringフレームワークを使用していない場合、Springコンテナーの範囲外のものを管理できないため、SpringAOPを使用するという考えを捨てるしかありません。 ただし、アプリケーションが完全にSpringフレームワークを使用して作成されている場合は、学習と適用が簡単であるため、SpringAOPを使用できます。
  • 柔軟性:ジョインポイントのサポートが限られているため、Spring AOPは完全なAOPソリューションではありませんが、プログラマーが直面する最も一般的な問題を解決します。 AOPをさらに深く掘り下げて最大限に活用し、利用可能なさまざまな参加ポイントからのサポートが必要な場合は、AspectJが選択されます。
  • パフォーマンス:限られた側面を使用している場合、パフォーマンスにはわずかな違いがあります。 ただし、アプリケーションに数万を超える側面がある場合があります。 このような場合はランタイムウィービングを使用したくないので、AspectJを選択することをお勧めします。 AspectJはSpringAOPより8〜35倍高速であることが知られています
  • 両方の長所:これらのフレームワークは両方とも完全に互換性があります。 可能な限りSpringAOPをいつでも利用でき、AspectJを使用して、前者ではサポートされていない参加ポイントをサポートできます。

6. 結論

この記事では、いくつかの重要な領域で、SpringAOPとAspectJの両方を分析しました。

AOPへの2つのアプローチを、柔軟性と、アプリケーションにどれだけ簡単に適合するかについて比較しました。