第10章 JBoss AOP

JBoss AOP は 100% Pure Java のアスペクト指向フレームワークで、すべてのプログラミング環境で使用することができ、アプリケーションサーバーと密に統合することが可能です。通常のオブジェクト指向プログラムでの対応が難しい場合でも、アスペクトはコードベースを簡単にモジュール化することができます アプリケーションロジックやシステムコードからクリーンに分離することができ、統合ポイントをソフトウェアへ公開する素晴らしい方法を提供します。 JDK 1.5 アノテーションを組み合わせると、コード生成にアノテーションのみを使用せずに、 クリーンでプラグ可能な方法で Java 言語を拡張できます。
JBoss AOP はフレームワークであるだけでなく、アノテーションやポイントカット表現経由で適用され、ランタイム時に動的に適用されるパッケージ済みのアスペクトセットでもあります。これには、キャッシング、非同期通信、トランザクション、セキュリティ、リモーティングなど、多数含まれます。
アスペクトは、 メソッド、 クラス、 オブジェクト階層、 オブジェクトモデル全体に散在する共通の機能です。 構造があるような動作をしますが、従来のオブジェクト指向技術では構造をコードで表現することはできません。
例えば、 メトリックスは共通のアスペクトの 1 つです。 アプリケーションより有用なログを生成するには、 コード全体に通知メッセージを散在させなければなりません。 しかし、 メトリックスはクラスやオブジェクトモデルが考慮されるものではありません。 顧客やアカウントを表すわけではなく、 ビジネスルールを実現しません。 メトリックスは直交で、 実際のアプリケーションとは無関係です。 

10.1. 主な用語

ジョインポイント

ジョインポイントとは Java プログラム内のポイントのことです。 メソッドの呼び出し、 コンストラクタの実行、 フィールドのアクセスはすべてジョインポイントとなります。 ジョインポイントは、 イベントがメソッド呼び出し、 コンストラクタコール、 フィールドアクセスなどである特定の Java イベントと考えることができます。

呼び出し

呼び出しは、 ランタイム時のジョインポイントをカプセル化する JBoss AOP クラスです。 呼び出されたメソッドやメソッドの引数などの情報が含まれます。

アドバイス

アドバイスは、 特定のジョインポイントが実行された時に呼び出されるメソッドのことです (メソッドが呼び出された時にトリガーされる動作など)。 インターセプションを行うコードと考えることもできます。 アドバイスは「イベントハンドラー」とも類似しています。 

ポイントカット

ポイントカットは AOP の表現言語です。 正規表現が文字列と一致するように、 ポイントカット表現もジョインポイントと一致します。 

イントロダクション

イントロダクションは Java クラスのタイプや構造を変更します。 既存のクラスにインターフェースを実装するよう強制、あるいは アノテーションを追加するために使用できます。 

アスペクト

アスペクトは、 アドバイス、 ポイントカット定義、 ミックスイン、 その他 JBoss AOP コンストラクトの数をカプセル化するプレーン Java クラスです。 

インターセプター

インターセプターinvoke という名前のアドバイスのみを持つアスペクトです。 インターフェースを実装するようクラスを強制してコードをチェックしたい場合に実装できるインターフェースです。 インターセプターは移植可能で、 EJB や JMX MBean など他の JBoss 環境で再使用することができます。

AOP では、 メトリックスなどの機能は横断的関心事 (crosscutting concern) と呼ばれます。 これは、オブジェクトモデルの複数のポイントを「横断」しながらも明確に異なる動作であるためです。 開発方法では、 横断的関心事を抽象化し、 カプセル化することが推奨されます。
アプリケーションにコードを追加し、 特定メソッドの呼び出しに掛かる時間を測定するとしましょう。 プレーン Java では、 以下のようなコードになるはずです。
public class BankAccountDAO
{
 public void withdraw(double amount)
 {
  long startTime = System.currentTimeMillis();
  try
  {
   // Actual method body...
  }
  finally
  {
   long endTime = System.currentTimeMillis() - startTime;
   System.out.println("withdraw took: " + endTime);
  }
 }
}
このコードでも動作しますが、いくつかの問題があります。
  1. try/finally ブロックのコードを手作業でベンチマーク対象のメソッドやコンストラクターすべてに追加する必要があるため、 メトリクスの有効化や無効化が大変難しくなります。
  2. プロファイリングコードをアプリケーション全体に散在させるべきではありません。try/finally ブロック内にタイミングが含まれるようにしなければならないため、 コードが膨張して読みにくくなります。
  3. この機能を拡張してメソッドや失敗数が含まれるようにし、 これらの統計を高性能なレポートメカニズムに登録したい場合、 多くのファイルを変更する必要があります。
コードベース全体にメトリクスが分散されるため、 メトリクスに対するこのアプローチは維持や拡張が大変難しくなります。 多くの場合、 メトリクスをクラスに追加するのに OOP が最良の方法であるとは言えません。
アスペクト指向プログラミングは、 このような動作機能をカプセル化する方法を提供します。 これにより、 メトリクスのような動作をコードの「周り」に追加することができます。 例えば、 コードの実際のボディーを実行する前に BankAccountDAO への呼び出しがメトリクスアスペクトを通過するよう指定するププログラム制御を AOP は提供します。