青木 正平(あおき しょうへい)
株式会社DTS ネットワーク事業本部所属。Struts/Springベースのフレームワーク開発,プロジェクト支援に携わる。
妻鳥 啓介(つまどり けいすけ)
株式会社DTS ネットワーク事業本部所属。Springを利用した業務開発に携わる。

 今回は,Springで提供されているAOP機能(以下,SpringAOP)について説明します。最初にAOPとは何なのか,どんなメリットがあるのかを簡単に説明します。次に,AOPの基本的な使い方を,サンプルを使って説明します。あなたが普通の業務開発者であるならば,このAOPの使い方を覚えるだけで十分でしょう。

 最後に,AOPを自分で作る(正確には「アドバイス」というものを作ります)という,少し高度なことに挑戦します。こちらはAOPを自作する必要が出たときに読めばよいと思います。それでは,さっそく始めましょう。

AOPとは

 AOPとは,アスペクト指向プログラミング(Aspect-Oriented Programming)のことで,オブジェクトが本来するべき処理と,本来するべきはない処理を分離するプログラミング手法のことです。

 ピンと来ない方は,商品検索のような業務処理をするクラスとトランザクション処理との関係を思い浮かべてください(図1)。商品検索というクラスには,本来,商品を検索するためのプログラムが書かれます。しかし,処理の途中でデータベースにアクセスする場合,データベース・コネクションの取得やトランザクション処理が必要になります。結果,商品検索クラスの中に,商品検索とは全く関係のないオマケの処理(トランザクション処理)が含まれてしまい,プログラムが見にくくなります。

図1●AOP適用前のクラス
図1●AOP適用前のクラス

 この問題は商品検索処理に限ったことではありません。商品登録処理や登録抹消処理のときも,同じようにトランザクション・コードが入り混じっています。つまり,似たようなトランザクション・コードがあちこちで重複するという問題も抱えているのです。

 もちろん,商品検索クラスの中にトランザクション処理が含まれていても,似たようなコードがあちこちにあっても,間違いではありません。しかし,これら二つの処理を別々に分けて管理でき,かつトランザクション処理のように重複したコードを一つのクラスにまとめることができれば,ソースコードはシンプルになり管理しやすくなるでしょう。そうです,この発想がAOPなのです。

 図2はAOPのイメージです。商品検索クラスには検索処理しかありませんし,トランザクション・クラスにはトランザクション処理しかありません。また,重複していたトランザクション・コードは一つのクラスにまとまっています。

図2●AOP適用後のクラス
図2●AOP適用後のクラス

 このようにすると,「商品検索処理とトランザクション処理を分離したら,トランザクションがかからなくなるのでは…」と不安に思う方もいるかもしれません。しかし,心配は要りません。分離された二つの処理は,実行時になると,あたかも一つのクラスだったかのように,ちゃんとトランザクションがかかります(図3)。

 つまり,AOPとは,クラス上では処理を役割ごとに分けておき,“実行時だけ”一つに合体するのです。二つに分けられた処理を合体させる具体的な方法については,後ほど説明します。

図3●AOP実行時のイメージ
図3●AOP実行時のイメージ

 もう一度,AOPのメリットを整理しましょう。前述の通り,本来の処理とオマケの処理を分離するため,プログラムがシンプルになり管理しやすくなります。また,別々の二つの処理を合体させることは,別の視点から見ると,トランザクションのようなオマケの処理を,“作成済みのクラスには一切手を入れずに”後から追加できる仕組みと言えます。

SpringAOPの使い方

 AOPのイメージがつかめたところで,今度はサンプルを見ながら,SpringAOPの使い方を説明したいと思います。ここでは,業務ロジックに見立てたBusinessLogicImplクラス(実際には文字列を出力するだけのメソッドを持つ)に,トレースログ(メソッドの開始時と終了時を知らせるだけのログ)を出力するというオマケ処理を加えてみます。トレースログを出力するクラスは,Springで提供されている「org.springframework.aop.interceptor.SimpleTraceInterceptorクラス」(以下,SimpleTraceInterceptorクラス)を使います。

 図4は,サンプル・プログラムのイメージです。Mainクラスが起動クラスです。プログラム上ではBusinessLogicインタフェースを呼び出していますが,実行時にはDIを使ってBusinessLogicImplが呼び出されます。そして,オマケ処理であるSimpleTraceInterceptorクラスは,プログラム上では完全に独立しています。

図4●サンプルのプログラム上のイメージ
図4●サンプルのプログラム上のイメージ

 次に,このサンプルを実行したときのイメージ(図5)を見てみましょう。Mainクラスが業務ロジックを呼び出すとき,オマケ処理であるSimpleTraceInterceptorクラスが突然しゃしゃり出てきているのがわかると思います。この「本来の処理が呼び出される直前に,オマケがしゃしゃり出てくる」がSpringAOPの特徴です。

図5●サンプルの実行時のイメージ
図5●サンプルの実行時のイメージ

 なお,オマケ処理の中では,本来の業務ロジックを呼び出すので,処理そのものが入れ替わるというわけではありません。

 プログラム上のイメージと,実行時のイメージをつかんだところで,サンプルの作り方を見ていきましょう。まず,作成するファイルは図6の通りです(srcはソースフォルダのルートになります)。

図6●サンプルのフォルダ構成
図6●サンプルのフォルダ構成

 サンプル・プロジェクトで使用するjarファイルは以下の通りです。Springをダウンロードすると,その中に同梱されています。なお,本稿で使用するSpringのバージョンは2.0.5です。このすべてのjarファイルをクラスパスに追加してください。

 spring.jar
 aspectjweaver.jar
 commons-logging-1.1.jar
 log4j-1.2.14.jar

 サンプルの作成手順は以下の通りです。順に説明します。

1.業務ロジッククラスを作る(本来の処理をするクラス)
2.Bean定義ファイルを作り,業務ロジッククラスの設定を記述
3.Bean定義ファイルにSimpleTraceInterceptorクラス(オマケ処理)の設定を記述
4.ログ出力用の設定ファイルを作る
5.メインクラスを作る