はじめに
オブジェクト指向プログラミング(OOP)のカプセル化、継承、多態性という概念は、よく使われる一連の動作をオブジェクトとその階層としてモデル化するために考案されたものです。そのため、それぞれのオブジェクトセットは特定の動作パターンを表すようにモデル化されます。しかしOOPでは、関連性のないオブジェクト間にまたがるような共通動作を効率よく表現することができません。そこで、同じコードセット(冗長なコード)がシステムのあちこちに散在することになります。
例えば、ロギングのケースを考えてみましょう。ロギングコードは、ほとんどの場合、複数のオブジェクト階層に対して横断的に散りばめられ、しかも、それらのオブジェクト階層との機能的な関連性も持ちません。つまり、OOPは上下方向(垂直方向)のオブジェクト関係を記述するのには適していますが、左右方向(水平方向)のオブジェクト関係を扱うには力不足です。アスペクト指向プログラミング(AOP)は、水平方向のオブジェクト関係を横断的関心事ととらえ、それを中心機能から分離することでこの問題に対処しています。
AOPは、静的横断(static crosscutting)と動的横断(dynamic crosscutting)を用いることで、オブジェクトモデルに設計時動作と実行時動作を簡単に追加できるようにする技術です。AOPを利用すると、ロギングのような横断的機能を実現するコードを記述し、それを(アノテーションすなわちXML宣言を用いて)既存のコードに宣言的に適用することができます。また、手元にソースコードがない(あるいは変更を許可するライセンスが付与されていない)サードパーティ製ソフトウェアのPOJO(Plain Old Java Object)にコードを注入するようなことも可能です。こうしてAOPは柔軟性の高い疎結合アーキテクチャを実現します。
アスペクトとしてのロギング
ロギングは、その性質的な特徴から、アスペクトとして実装すべき機能の最有力候補とされています。特に重要な性質は次の2つです。
- 多くの場合、ロギングコードはアプリケーションのいたる所で複製され、アプリケーション内の複数のコンポーネントにまたがって大量の冗長コードが生じる原因になります。ロギングのロジックを独立したモジュールとして抽象化し、さまざまなコンポーネントから1回のメソッド呼び出しで実行できる形にしたとしても、その1回のメソッド呼び出しがあちこちで繰り返されることになります。
- ロギングロジックはビジネス機能を提供するものでなく、アプリケーションのビジネスドメインとは無関係です。
ロギング機能を複数のコンポーネントにまたがらせると、コードが複雑になります。図1は、この様子を示しています。左側の3つのビジネスオブジェクトは、ビジネス機能をカプセル化しています。これらのオブジェクトは、ビジネスタスクを実行するだけでなく、ロギング機能やセキュリティ、トランザクション、キャッシングなどの横断的関心事も扱っています。
AOPは、こうした横断的なサービスをモジュール化し、対象となるコンポーネントに宣言的に適用できるようにします。これでビジネスコンポーネントはそれぞれのビジネスタスクに専念でき、周辺のシステムサービスのことを忘れることができます。アスペクトは、アプリケーションの多くのコンポーネントを覆う毛布のようなものと考えられます(図2を参照)。この「毛布」の中にアプリケーションの中心機能と各種のコンポーネントが一緒にくるまれており、これらのコンポーネントに対してアスペクトを宣言的に適用することができます。アスペクトがコード内のどこに注入されるかはAOPによって特定され、各コンポーネントは関知しません。アスペクトが実際に注入される場所は「ポイントカット」と呼ばれます。アスペクトは、コンパイル時または実行時にポイントカットに注入されます(注入のタイミングは、使用するAOPフレームワークに応じて異なります)。実際、AOPを利用すると、オブジェクト側がまったく知らない新機能でもオブジェクトに注入することができます。これはシステムの柔軟性やスケーラビリティ、メンテナンス性を高める非常に効果的な概念です。
以降で紹介するサンプルでは、AOPフレームワークとしてSpringを使用します。
AOPフレームワークとしてのSpring
Springはプロキシベースの手法を用いてアスペクトをオブジェクトモデルと結び付けます。つまり、アスペクト化されたオブジェクトに対するすべてのメソッド呼び出しをインターセプトし、目的のオブジェクトに対するメソッド呼び出しを代行(プロキシ)します。アプリケーションからビジネスオブジェクトに対するメソッド呼び出しが発行されると、Springはそのメソッド呼び出しをインターセプトし、編み込まれた横断的なアスペクトを適用したうえで、目的のオブジェクトに対してメソッド呼び出しを発行します。これはEJBフレームワークとよく似ています。EJBフレームワークではEJBコンテナがEJBコンポーネントへの呼び出しをインターセプトし、所定の横断的動作(セキュリティチェック、トランザクションなど)を適用したうえで、目的のEJB
オブジェクトを起動します。アスペクトの定義と適用はXML構成ファイルを用いて行われます。